From 58b81db9aeb05da744b0ee8a72744c38dba7593a Mon Sep 17 00:00:00 2001 From: Vansh Wassan <007blackhacker@gmail.com> Date: Fri, 8 Dec 2023 08:07:54 +0530 Subject: [PATCH 1/9] Deployed protocol contracts on lightlink-goerli --- .../lightlink-goerli-testnet/.chainId | 1 + .../AccessControlRegistry.json | 535 ++++++++ .../AirnodeRrpV0.json | 1184 +++++++++++++++++ .../AirnodeRrpV0DryRun.json | 163 +++ .../RequesterAuthorizerWithAirnode.json | 912 +++++++++++++ .../d8591a026515856ab7bc7dc284bf2fbe.json | 189 +++ .../deployments/references.json | 9 + 7 files changed, 2993 insertions(+) create mode 100644 packages/airnode-protocol/deployments/lightlink-goerli-testnet/.chainId create mode 100644 packages/airnode-protocol/deployments/lightlink-goerli-testnet/AccessControlRegistry.json create mode 100644 packages/airnode-protocol/deployments/lightlink-goerli-testnet/AirnodeRrpV0.json create mode 100644 packages/airnode-protocol/deployments/lightlink-goerli-testnet/AirnodeRrpV0DryRun.json create mode 100644 packages/airnode-protocol/deployments/lightlink-goerli-testnet/RequesterAuthorizerWithAirnode.json create mode 100644 packages/airnode-protocol/deployments/lightlink-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json diff --git a/packages/airnode-protocol/deployments/lightlink-goerli-testnet/.chainId b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/.chainId new file mode 100644 index 0000000000..ab6a66639c --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/.chainId @@ -0,0 +1 @@ +1891 \ No newline at end of file diff --git a/packages/airnode-protocol/deployments/lightlink-goerli-testnet/AccessControlRegistry.json b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/AccessControlRegistry.json new file mode 100644 index 0000000000..05fe8fdc69 --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/AccessControlRegistry.json @@ -0,0 +1,535 @@ +{ + "address": "0x92E5125adF385d86beDb950793526106143b6Df1", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "rootRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "InitializedManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "InitializedRole", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "name": "deriveRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "deriveRootRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "rootRole", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "initializeManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "name": "initializeRoleAndGrantToSender", + "outputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x044867e3763b0a274563ed3494228a787ef7900f399adb0da2cf614417dfb128", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xc97965EbD0f2123Cc31BEc63E18A8Ce9Ef6a1e7e", + "contractAddress": "0x0000000000000000000000000000000000000000", + "transactionIndex": 0, + "gasUsed": "1006525", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xd1ca575f6f5ba33fc7cee462181ec119b2071a776e0da309ab83336457ef47ba", + "transactionHash": "0x044867e3763b0a274563ed3494228a787ef7900f399adb0da2cf614417dfb128", + "logs": [], + "blockNumber": 56898222, + "cumulativeGasUsed": "1006525", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "d8591a026515856ab7bc7dc284bf2fbe", + "metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"rootRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"manager\",\"type\":\"address\"}],\"name\":\"InitializedManager\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"adminRole\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"InitializedRole\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"adminRole\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"}],\"name\":\"deriveRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"manager\",\"type\":\"address\"}],\"name\":\"deriveRootRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"rootRole\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"manager\",\"type\":\"address\"}],\"name\":\"initializeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"adminRole\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"}],\"name\":\"initializeRoleAndGrantToSender\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Each user is called a \\\"manager\\\", and is the only member of their root role. Starting from this root role, they can create an arbitrary tree of roles and grant these to accounts. Each role has a description, and roles adminned by the same role cannot have the same description.\",\"kind\":\"dev\",\"methods\":{\"deriveRole(bytes32,string)\":{\"details\":\"This implies that roles adminned by the same role cannot have the same description\",\"params\":{\"adminRole\":\"Admin role\",\"description\":\"Human-readable description of the role\"},\"returns\":{\"role\":\"Role\"}},\"deriveRootRole(address)\":{\"params\":{\"manager\":\"Manager address\"},\"returns\":{\"rootRole\":\"Root role\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"initializeManager(address)\":{\"details\":\"Anyone can initialize a manager. An uninitialized manager attempting to initialize a role will be initialized automatically. Once a manager is initialized, subsequent initializations have no effect.\",\"params\":{\"manager\":\"Manager address to be initialized\"}},\"initializeRoleAndGrantToSender(bytes32,string)\":{\"details\":\"If the sender should not have the initialized role, they should explicitly renounce it after initializing it. Once a role is initialized, subsequent initializations have no effect other than granting the role to the sender. The sender must be a member of `adminRole`. `adminRole` value is not validated because the sender cannot have the `bytes32(0)` role. If the sender is an uninitialized manager that is initializing a role directly under their root role, manager initialization will happen automatically, which will grant the sender `adminRole` and allow them to initialize the role.\",\"params\":{\"adminRole\":\"Admin role to be assigned to the initialized role\",\"description\":\"Human-readable description of the initialized role\"},\"returns\":{\"role\":\"Initialized role\"}},\"multicall(bytes[])\":{\"details\":\"Receives and executes a batch of function calls on this contract.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Overriden to disallow managers to renounce their root roles. `role` and `account` are not validated because `AccessControl.renounceRole` will revert if either of them is zero.\",\"params\":{\"account\":\"Account to renounce the role\",\"role\":\"Role to be renounced\"}},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"title\":\"Contract that allows users to manage independent, tree-shaped access control tables\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deriveRole(bytes32,string)\":{\"notice\":\"Derives the role using its admin role and description\"},\"deriveRootRole(address)\":{\"notice\":\"Derives the root role of the manager\"},\"initializeManager(address)\":{\"notice\":\"Initializes the manager by initializing its root role and granting it to them\"},\"initializeRoleAndGrantToSender(bytes32,string)\":{\"notice\":\"Initializes a role by setting its admin role and grants it to the sender\"},\"renounceRole(bytes32,address)\":{\"notice\":\"Called by the account to renounce the role\"}},\"notice\":\"Multiple contracts can refer to this contract to check if their users have granted accounts specific roles. Therefore, it aims to keep all access control roles of its users in this single contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/access-control-registry/AccessControlRegistry.sol\":\"AccessControlRegistry\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/AccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControl.sol\\\";\\nimport \\\"../utils/Context.sol\\\";\\nimport \\\"../utils/Strings.sol\\\";\\nimport \\\"../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 * ```\\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 * ```\\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.\\n */\\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\\n struct RoleData {\\n mapping(address => bool) members;\\n bytes32 adminRole;\\n }\\n\\n mapping(bytes32 => 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 a standardized message including the required role.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n *\\n * _Available since v4.1._\\n */\\n modifier onlyRole(bytes32 role) {\\n _checkRole(role, _msgSender());\\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 override returns (bool) {\\n return _roles[role].members[account];\\n }\\n\\n /**\\n * @dev Revert with a standard message if `account` is missing `role`.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n */\\n function _checkRole(bytes32 role, address account) internal view {\\n if (!hasRole(role, account)) {\\n revert(\\n string(\\n abi.encodePacked(\\n \\\"AccessControl: account \\\",\\n Strings.toHexString(uint160(account), 20),\\n \\\" is missing role \\\",\\n Strings.toHexString(uint256(role), 32)\\n )\\n )\\n );\\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 override 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 function grantRole(bytes32 role, address account) public virtual override 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 function revokeRole(bytes32 role, address account) public virtual override 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 `account`.\\n */\\n function renounceRole(bytes32 role, address account) public virtual override {\\n require(account == _msgSender(), \\\"AccessControl: can only renounce roles for self\\\");\\n\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event. Note that unlike {grantRole}, this function doesn't perform any\\n * checks on the calling account.\\n *\\n * [WARNING]\\n * ====\\n * This function should only be called from the constructor when setting\\n * up the initial roles for the system.\\n *\\n * Using this function in any other way is effectively circumventing the admin\\n * system imposed by {AccessControl}.\\n * ====\\n *\\n * NOTE: This function is deprecated in favor of {_grantRole}.\\n */\\n function _setupRole(bytes32 role, address account) internal virtual {\\n _grantRole(role, account);\\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 Grants `role` to `account`.\\n *\\n * Internal function without access restriction.\\n */\\n function _grantRole(bytes32 role, address account) internal virtual {\\n if (!hasRole(role, account)) {\\n _roles[role].members[account] = true;\\n emit RoleGranted(role, account, _msgSender());\\n }\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * Internal function without access restriction.\\n */\\n function _revokeRole(bytes32 role, address account) internal virtual {\\n if (hasRole(role, account)) {\\n _roles[role].members[account] = false;\\n emit RoleRevoked(role, account, _msgSender());\\n }\\n }\\n}\\n\",\"keccak256\":\"0xb9a137b317dc4806805f2259686186c0c053c32d80fe9c15ecdbf2eb1cf52849\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\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 * _Available since v3.1._\\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 `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Multicall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Multicall.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @dev Provides a function to batch together multiple calls in a single external call.\\n *\\n * _Available since v4.1._\\n */\\nabstract contract Multicall {\\n /**\\n * @dev Receives and executes a batch of function calls on this contract.\\n */\\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n results[i] = Address.functionDelegateCall(address(this), data[i]);\\n }\\n return results;\\n }\\n}\\n\",\"keccak256\":\"0x768ccb0d556d2edde43cf5fc16860a936ce91eca96be0cf9e807ffe875f6f516\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./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 *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\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\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"contracts/access-control-registry/AccessControlRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"@openzeppelin/contracts/utils/Multicall.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/AccessControl.sol\\\";\\nimport \\\"./RoleDeriver.sol\\\";\\nimport \\\"./interfaces/IAccessControlRegistry.sol\\\";\\n\\n/// @title Contract that allows users to manage independent, tree-shaped access\\n/// control tables\\n/// @notice Multiple contracts can refer to this contract to check if their\\n/// users have granted accounts specific roles. Therefore, it aims to keep all\\n/// access control roles of its users in this single contract.\\n/// @dev Each user is called a \\\"manager\\\", and is the only member of their root\\n/// role. Starting from this root role, they can create an arbitrary tree of\\n/// roles and grant these to accounts. Each role has a description, and roles\\n/// adminned by the same role cannot have the same description.\\ncontract AccessControlRegistry is\\n Multicall,\\n AccessControl,\\n RoleDeriver,\\n IAccessControlRegistry\\n{\\n /// @notice Initializes the manager by initializing its root role and\\n /// granting it to them\\n /// @dev Anyone can initialize a manager. An uninitialized manager\\n /// attempting to initialize a role will be initialized automatically.\\n /// Once a manager is initialized, subsequent initializations have no\\n /// effect.\\n /// @param manager Manager address to be initialized\\n function initializeManager(address manager) public override {\\n require(manager != address(0), \\\"Manager address zero\\\");\\n bytes32 rootRole = deriveRootRole(manager);\\n if (!hasRole(rootRole, manager)) {\\n _grantRole(rootRole, manager);\\n emit InitializedManager(rootRole, manager);\\n }\\n }\\n\\n /// @notice Called by the account to renounce the role\\n /// @dev Overriden to disallow managers to renounce their root roles.\\n /// `role` and `account` are not validated because\\n /// `AccessControl.renounceRole` will revert if either of them is zero.\\n /// @param role Role to be renounced\\n /// @param account Account to renounce the role\\n function renounceRole(bytes32 role, address account)\\n public\\n override(AccessControl, IAccessControl)\\n {\\n require(\\n role != deriveRootRole(account),\\n \\\"role is root role of account\\\"\\n );\\n AccessControl.renounceRole(role, account);\\n }\\n\\n /// @notice Initializes a role by setting its admin role and grants it to\\n /// the sender\\n /// @dev If the sender should not have the initialized role, they should\\n /// explicitly renounce it after initializing it.\\n /// Once a role is initialized, subsequent initializations have no effect\\n /// other than granting the role to the sender.\\n /// The sender must be a member of `adminRole`. `adminRole` value is not\\n /// validated because the sender cannot have the `bytes32(0)` role.\\n /// If the sender is an uninitialized manager that is initializing a role\\n /// directly under their root role, manager initialization will happen\\n /// automatically, which will grant the sender `adminRole` and allow them\\n /// to initialize the role.\\n /// @param adminRole Admin role to be assigned to the initialized role\\n /// @param description Human-readable description of the initialized role\\n /// @return role Initialized role\\n function initializeRoleAndGrantToSender(\\n bytes32 adminRole,\\n string calldata description\\n ) external override returns (bytes32 role) {\\n require(bytes(description).length > 0, \\\"Role description empty\\\");\\n role = deriveRole(adminRole, description);\\n // AccessControl roles have `DEFAULT_ADMIN_ROLE` (i.e., `bytes32(0)`)\\n // as their `adminRole` by default. No account in AccessControlRegistry\\n // can possibly have that role, which means all initialized roles will\\n // have non-default admin roles, and vice versa.\\n if (getRoleAdmin(role) == DEFAULT_ADMIN_ROLE) {\\n if (adminRole == deriveRootRole(_msgSender())) {\\n initializeManager(_msgSender());\\n }\\n _setRoleAdmin(role, adminRole);\\n emit InitializedRole(role, adminRole, description, _msgSender());\\n }\\n grantRole(role, _msgSender());\\n }\\n\\n /// @notice Derives the root role of the manager\\n /// @param manager Manager address\\n /// @return rootRole Root role\\n function deriveRootRole(address manager)\\n public\\n pure\\n override\\n returns (bytes32 rootRole)\\n {\\n rootRole = _deriveRootRole(manager);\\n }\\n\\n /// @notice Derives the role using its admin role and description\\n /// @dev This implies that roles adminned by the same role cannot have the\\n /// same description\\n /// @param adminRole Admin role\\n /// @param description Human-readable description of the role\\n /// @return role Role\\n function deriveRole(bytes32 adminRole, string calldata description)\\n public\\n pure\\n override\\n returns (bytes32 role)\\n {\\n role = _deriveRole(adminRole, description);\\n }\\n}\\n\",\"keccak256\":\"0xc51bc818b977ba6e35c57da374da9727c1f103c54e1fb3725fbe419bfba4d39c\",\"license\":\"MIT\"},\"contracts/access-control-registry/RoleDeriver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @title Contract to be inherited by contracts that will derive\\n/// AccessControlRegistry roles\\n/// @notice If a contract interfaces with AccessControlRegistry and needs to\\n/// derive roles, it should inherit this contract instead of re-implementing\\n/// the logic\\ncontract RoleDeriver {\\n /// @notice Derives the root role of the manager\\n /// @param manager Manager address\\n /// @return rootRole Root role\\n function _deriveRootRole(address manager)\\n internal\\n pure\\n returns (bytes32 rootRole)\\n {\\n rootRole = keccak256(abi.encodePacked(manager));\\n }\\n\\n /// @notice Derives the role using its admin role and description\\n /// @dev This implies that roles adminned by the same role cannot have the\\n /// same description\\n /// @param adminRole Admin role\\n /// @param description Human-readable description of the role\\n /// @return role Role\\n function _deriveRole(bytes32 adminRole, string memory description)\\n internal\\n pure\\n returns (bytes32 role)\\n {\\n role = _deriveRole(adminRole, keccak256(abi.encodePacked(description)));\\n }\\n\\n /// @notice Derives the role using its admin role and description hash\\n /// @dev This implies that roles adminned by the same role cannot have the\\n /// same description\\n /// @param adminRole Admin role\\n /// @param descriptionHash Hash of the human-readable description of the\\n /// role\\n /// @return role Role\\n function _deriveRole(bytes32 adminRole, bytes32 descriptionHash)\\n internal\\n pure\\n returns (bytes32 role)\\n {\\n role = keccak256(abi.encodePacked(adminRole, descriptionHash));\\n }\\n}\\n\",\"keccak256\":\"0x20fe9d6cce9a1e4fe0b5bd8868fabbe6ee9db7fa8154bcf6316005307d63ee04\",\"license\":\"MIT\"},\"contracts/access-control-registry/interfaces/IAccessControlRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/IAccessControl.sol\\\";\\n\\ninterface IAccessControlRegistry is IAccessControl {\\n event InitializedManager(bytes32 indexed rootRole, address indexed manager);\\n\\n event InitializedRole(\\n bytes32 indexed role,\\n bytes32 indexed adminRole,\\n string description,\\n address sender\\n );\\n\\n function initializeManager(address manager) external;\\n\\n function initializeRoleAndGrantToSender(\\n bytes32 adminRole,\\n string calldata description\\n ) external returns (bytes32 role);\\n\\n function deriveRootRole(address manager)\\n external\\n pure\\n returns (bytes32 rootRole);\\n\\n function deriveRole(bytes32 adminRole, string calldata description)\\n external\\n pure\\n returns (bytes32 role);\\n}\\n\",\"keccak256\":\"0x51b6c37b03f81667920dac10d53efc75e403c11348e71311b39a25c9b1cfdf76\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50611145806100206000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063805d43fc11610081578063ac9650d81161005b578063ac9650d8146101d2578063b530b5e0146101f2578063d547741f1461020557600080fd5b8063805d43fc1461018057806391d1485414610193578063a217fddf146101ca57600080fd5b806336568abe116100b257806336568abe1461014757806373e983621461015a5780637f7120fe1461016d57600080fd5b806301ffc9a7146100d9578063248a9ca3146101015780632f2ff15d14610132575b600080fd5b6100ec6100e7366004610c90565b610218565b60405190151581526020015b60405180910390f35b61012461010f366004610cd2565b60009081526020819052604090206001015490565b6040519081526020016100f8565b610145610140366004610d07565b6102b1565b005b610145610155366004610d07565b6102dc565b610124610168366004610d33565b610347565b61014561017b366004610daf565b61042e565b61012461018e366004610daf565b6104fe565b6100ec6101a1366004610d07565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b610124600081565b6101e56101e0366004610dca565b61053e565b6040516100f89190610e9b565b610124610200366004610d33565b610633565b610145610213366004610d07565b61067d565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806102ab57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000828152602081905260409020600101546102cd81336106a3565b6102d78383610721565b505050565b6102e5816104fe565b8214156103395760405162461bcd60e51b815260206004820152601c60248201527f726f6c6520697320726f6f7420726f6c65206f66206163636f756e740000000060448201526064015b60405180910390fd5b61034382826107bf565b5050565b6000816103965760405162461bcd60e51b815260206004820152601660248201527f526f6c65206465736372697074696f6e20656d707479000000000000000000006044820152606401610330565b6103a1848484610633565b600081815260208190526040812060010154919250141561041d576103c5336104fe565b8414156103d5576103d53361042e565b6103df8185610847565b83817f532ead3ec09896bef1351791fbaad86ac03f3204090a8e7f173f41414b1fdac085853360405161041493929190610efd565b60405180910390a35b61042781336102b1565b9392505050565b6001600160a01b0381166104845760405162461bcd60e51b815260206004820152601460248201527f4d616e616765722061646472657373207a65726f0000000000000000000000006044820152606401610330565b600061048f826104fe565b6000818152602081815260408083206001600160a01b038716845290915290205490915060ff16610343576104c48183610721565b6040516001600160a01b0383169082907f888b171f3b02386c0e4d8c85108dcb8d0ecdad2f274ddc7ce3914282538bdd8890600090a35050565b60408051606083901b6bffffffffffffffffffffffff191660208083019190915282516014818403018152603490920190925280519101206000906102ab565b60608167ffffffffffffffff81111561055957610559610f3f565b60405190808252806020026020018201604052801561058c57816020015b60608152602001906001900390816105775790505b50905060005b8281101561062c576105fc308585848181106105b0576105b0610f55565b90506020028101906105c29190610f6b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061089292505050565b82828151811061060e5761060e610f55565b6020026020010181905250808061062490610fcf565b915050610592565b5092915050565b60006106758484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506108b792505050565b949350505050565b60008281526020819052604090206001015461069981336106a3565b6102d7838361090c565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610343576106df816001600160a01b0316601461098b565b6106ea83602061098b565b6040516020016106fb929190610fea565b60408051601f198184030181529082905262461bcd60e51b82526103309160040161106b565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610343576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561077b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b038116331461083d5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610330565b610343828261090c565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b606061042783836040518060600160405280602781526020016110e960279139610b6c565b600061042783836040516020016108ce919061107e565b60408051601f198184030181528282528051602091820120838201949094528282019390935280518083038201815260609092019052805191012090565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610343576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6060600061099a83600261109a565b6109a59060026110b9565b67ffffffffffffffff8111156109bd576109bd610f3f565b6040519080825280601f01601f1916602001820160405280156109e7576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110610a1e57610a1e610f55565b60200101906001600160f81b031916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110610a6957610a69610f55565b60200101906001600160f81b031916908160001a9053506000610a8d84600261109a565b610a989060016110b9565b90505b6001811115610b1d577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110610ad957610ad9610f55565b1a60f81b828281518110610aef57610aef610f55565b60200101906001600160f81b031916908160001a90535060049490941c93610b16816110d1565b9050610a9b565b5083156104275760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610330565b6060833b610be25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610330565b600080856001600160a01b031685604051610bfd919061107e565b600060405180830381855af49150503d8060008114610c38576040519150601f19603f3d011682016040523d82523d6000602084013e610c3d565b606091505b5091509150610c4d828286610c57565b9695505050505050565b60608315610c66575081610427565b825115610c765782518084602001fd5b8160405162461bcd60e51b8152600401610330919061106b565b600060208284031215610ca257600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461042757600080fd5b600060208284031215610ce457600080fd5b5035919050565b80356001600160a01b0381168114610d0257600080fd5b919050565b60008060408385031215610d1a57600080fd5b82359150610d2a60208401610ceb565b90509250929050565b600080600060408486031215610d4857600080fd5b83359250602084013567ffffffffffffffff80821115610d6757600080fd5b818601915086601f830112610d7b57600080fd5b813581811115610d8a57600080fd5b876020828501011115610d9c57600080fd5b6020830194508093505050509250925092565b600060208284031215610dc157600080fd5b61042782610ceb565b60008060208385031215610ddd57600080fd5b823567ffffffffffffffff80821115610df557600080fd5b818501915085601f830112610e0957600080fd5b813581811115610e1857600080fd5b8660208260051b8501011115610e2d57600080fd5b60209290920196919550909350505050565b60005b83811015610e5a578181015183820152602001610e42565b83811115610e69576000848401525b50505050565b60008151808452610e87816020860160208601610e3f565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ef057603f19888603018452610ede858351610e6f565b94509285019290850190600101610ec2565b5092979650505050505050565b604081528260408201528284606083013760006060848301015260006060601f19601f86011683010190506001600160a01b0383166020830152949350505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112610f8257600080fd5b83018035915067ffffffffffffffff821115610f9d57600080fd5b602001915036819003821315610fb257600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415610fe357610fe3610fb9565b5060010190565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611022816017850160208801610e3f565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161105f816028840160208801610e3f565b01602801949350505050565b6020815260006104276020830184610e6f565b60008251611090818460208701610e3f565b9190910192915050565b60008160001904831182151516156110b4576110b4610fb9565b500290565b600082198211156110cc576110cc610fb9565b500190565b6000816110e0576110e0610fb9565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207cc002eec550ca333e5647aeee1bec01baf44cbf2540ae519fcdad161591c81864736f6c63430008090033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100d45760003560e01c8063805d43fc11610081578063ac9650d81161005b578063ac9650d8146101d2578063b530b5e0146101f2578063d547741f1461020557600080fd5b8063805d43fc1461018057806391d1485414610193578063a217fddf146101ca57600080fd5b806336568abe116100b257806336568abe1461014757806373e983621461015a5780637f7120fe1461016d57600080fd5b806301ffc9a7146100d9578063248a9ca3146101015780632f2ff15d14610132575b600080fd5b6100ec6100e7366004610c90565b610218565b60405190151581526020015b60405180910390f35b61012461010f366004610cd2565b60009081526020819052604090206001015490565b6040519081526020016100f8565b610145610140366004610d07565b6102b1565b005b610145610155366004610d07565b6102dc565b610124610168366004610d33565b610347565b61014561017b366004610daf565b61042e565b61012461018e366004610daf565b6104fe565b6100ec6101a1366004610d07565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b610124600081565b6101e56101e0366004610dca565b61053e565b6040516100f89190610e9b565b610124610200366004610d33565b610633565b610145610213366004610d07565b61067d565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806102ab57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000828152602081905260409020600101546102cd81336106a3565b6102d78383610721565b505050565b6102e5816104fe565b8214156103395760405162461bcd60e51b815260206004820152601c60248201527f726f6c6520697320726f6f7420726f6c65206f66206163636f756e740000000060448201526064015b60405180910390fd5b61034382826107bf565b5050565b6000816103965760405162461bcd60e51b815260206004820152601660248201527f526f6c65206465736372697074696f6e20656d707479000000000000000000006044820152606401610330565b6103a1848484610633565b600081815260208190526040812060010154919250141561041d576103c5336104fe565b8414156103d5576103d53361042e565b6103df8185610847565b83817f532ead3ec09896bef1351791fbaad86ac03f3204090a8e7f173f41414b1fdac085853360405161041493929190610efd565b60405180910390a35b61042781336102b1565b9392505050565b6001600160a01b0381166104845760405162461bcd60e51b815260206004820152601460248201527f4d616e616765722061646472657373207a65726f0000000000000000000000006044820152606401610330565b600061048f826104fe565b6000818152602081815260408083206001600160a01b038716845290915290205490915060ff16610343576104c48183610721565b6040516001600160a01b0383169082907f888b171f3b02386c0e4d8c85108dcb8d0ecdad2f274ddc7ce3914282538bdd8890600090a35050565b60408051606083901b6bffffffffffffffffffffffff191660208083019190915282516014818403018152603490920190925280519101206000906102ab565b60608167ffffffffffffffff81111561055957610559610f3f565b60405190808252806020026020018201604052801561058c57816020015b60608152602001906001900390816105775790505b50905060005b8281101561062c576105fc308585848181106105b0576105b0610f55565b90506020028101906105c29190610f6b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061089292505050565b82828151811061060e5761060e610f55565b6020026020010181905250808061062490610fcf565b915050610592565b5092915050565b60006106758484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506108b792505050565b949350505050565b60008281526020819052604090206001015461069981336106a3565b6102d7838361090c565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610343576106df816001600160a01b0316601461098b565b6106ea83602061098b565b6040516020016106fb929190610fea565b60408051601f198184030181529082905262461bcd60e51b82526103309160040161106b565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610343576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561077b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b038116331461083d5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610330565b610343828261090c565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b606061042783836040518060600160405280602781526020016110e960279139610b6c565b600061042783836040516020016108ce919061107e565b60408051601f198184030181528282528051602091820120838201949094528282019390935280518083038201815260609092019052805191012090565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610343576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6060600061099a83600261109a565b6109a59060026110b9565b67ffffffffffffffff8111156109bd576109bd610f3f565b6040519080825280601f01601f1916602001820160405280156109e7576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110610a1e57610a1e610f55565b60200101906001600160f81b031916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110610a6957610a69610f55565b60200101906001600160f81b031916908160001a9053506000610a8d84600261109a565b610a989060016110b9565b90505b6001811115610b1d577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110610ad957610ad9610f55565b1a60f81b828281518110610aef57610aef610f55565b60200101906001600160f81b031916908160001a90535060049490941c93610b16816110d1565b9050610a9b565b5083156104275760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610330565b6060833b610be25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610330565b600080856001600160a01b031685604051610bfd919061107e565b600060405180830381855af49150503d8060008114610c38576040519150601f19603f3d011682016040523d82523d6000602084013e610c3d565b606091505b5091509150610c4d828286610c57565b9695505050505050565b60608315610c66575081610427565b825115610c765782518084602001fd5b8160405162461bcd60e51b8152600401610330919061106b565b600060208284031215610ca257600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461042757600080fd5b600060208284031215610ce457600080fd5b5035919050565b80356001600160a01b0381168114610d0257600080fd5b919050565b60008060408385031215610d1a57600080fd5b82359150610d2a60208401610ceb565b90509250929050565b600080600060408486031215610d4857600080fd5b83359250602084013567ffffffffffffffff80821115610d6757600080fd5b818601915086601f830112610d7b57600080fd5b813581811115610d8a57600080fd5b876020828501011115610d9c57600080fd5b6020830194508093505050509250925092565b600060208284031215610dc157600080fd5b61042782610ceb565b60008060208385031215610ddd57600080fd5b823567ffffffffffffffff80821115610df557600080fd5b818501915085601f830112610e0957600080fd5b813581811115610e1857600080fd5b8660208260051b8501011115610e2d57600080fd5b60209290920196919550909350505050565b60005b83811015610e5a578181015183820152602001610e42565b83811115610e69576000848401525b50505050565b60008151808452610e87816020860160208601610e3f565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ef057603f19888603018452610ede858351610e6f565b94509285019290850190600101610ec2565b5092979650505050505050565b604081528260408201528284606083013760006060848301015260006060601f19601f86011683010190506001600160a01b0383166020830152949350505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112610f8257600080fd5b83018035915067ffffffffffffffff821115610f9d57600080fd5b602001915036819003821315610fb257600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415610fe357610fe3610fb9565b5060010190565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611022816017850160208801610e3f565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161105f816028840160208801610e3f565b01602801949350505050565b6020815260006104276020830184610e6f565b60008251611090818460208701610e3f565b9190910192915050565b60008160001904831182151516156110b4576110b4610fb9565b500290565b600082198211156110cc576110cc610fb9565b500190565b6000816110e0576110e0610fb9565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207cc002eec550ca333e5647aeee1bec01baf44cbf2540ae519fcdad161591c81864736f6c63430008090033", + "devdoc": { + "details": "Each user is called a \"manager\", and is the only member of their root role. Starting from this root role, they can create an arbitrary tree of roles and grant these to accounts. Each role has a description, and roles adminned by the same role cannot have the same description.", + "kind": "dev", + "methods": { + "deriveRole(bytes32,string)": { + "details": "This implies that roles adminned by the same role cannot have the same description", + "params": { + "adminRole": "Admin role", + "description": "Human-readable description of the role" + }, + "returns": { + "role": "Role" + } + }, + "deriveRootRole(address)": { + "params": { + "manager": "Manager address" + }, + "returns": { + "rootRole": "Root role" + } + }, + "getRoleAdmin(bytes32)": { + "details": "Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}." + }, + "grantRole(bytes32,address)": { + "details": "Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role." + }, + "hasRole(bytes32,address)": { + "details": "Returns `true` if `account` has been granted `role`." + }, + "initializeManager(address)": { + "details": "Anyone can initialize a manager. An uninitialized manager attempting to initialize a role will be initialized automatically. Once a manager is initialized, subsequent initializations have no effect.", + "params": { + "manager": "Manager address to be initialized" + } + }, + "initializeRoleAndGrantToSender(bytes32,string)": { + "details": "If the sender should not have the initialized role, they should explicitly renounce it after initializing it. Once a role is initialized, subsequent initializations have no effect other than granting the role to the sender. The sender must be a member of `adminRole`. `adminRole` value is not validated because the sender cannot have the `bytes32(0)` role. If the sender is an uninitialized manager that is initializing a role directly under their root role, manager initialization will happen automatically, which will grant the sender `adminRole` and allow them to initialize the role.", + "params": { + "adminRole": "Admin role to be assigned to the initialized role", + "description": "Human-readable description of the initialized role" + }, + "returns": { + "role": "Initialized role" + } + }, + "multicall(bytes[])": { + "details": "Receives and executes a batch of function calls on this contract." + }, + "renounceRole(bytes32,address)": { + "details": "Overriden to disallow managers to renounce their root roles. `role` and `account` are not validated because `AccessControl.renounceRole` will revert if either of them is zero.", + "params": { + "account": "Account to renounce the role", + "role": "Role to be renounced" + } + }, + "revokeRole(bytes32,address)": { + "details": "Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role." + }, + "supportsInterface(bytes4)": { + "details": "See {IERC165-supportsInterface}." + } + }, + "title": "Contract that allows users to manage independent, tree-shaped access control tables", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "deriveRole(bytes32,string)": { + "notice": "Derives the role using its admin role and description" + }, + "deriveRootRole(address)": { + "notice": "Derives the root role of the manager" + }, + "initializeManager(address)": { + "notice": "Initializes the manager by initializing its root role and granting it to them" + }, + "initializeRoleAndGrantToSender(bytes32,string)": { + "notice": "Initializes a role by setting its admin role and grants it to the sender" + }, + "renounceRole(bytes32,address)": { + "notice": "Called by the account to renounce the role" + } + }, + "notice": "Multiple contracts can refer to this contract to check if their users have granted accounts specific roles. Therefore, it aims to keep all access control roles of its users in this single contract.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 24, + "contract": "contracts/access-control-registry/AccessControlRegistry.sol:AccessControlRegistry", + "label": "_roles", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_struct(RoleData)19_storage)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_bytes32,t_struct(RoleData)19_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct AccessControl.RoleData)", + "numberOfBytes": "32", + "value": "t_struct(RoleData)19_storage" + }, + "t_struct(RoleData)19_storage": { + "encoding": "inplace", + "label": "struct AccessControl.RoleData", + "members": [ + { + "astId": 16, + "contract": "contracts/access-control-registry/AccessControlRegistry.sol:AccessControlRegistry", + "label": "members", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 18, + "contract": "contracts/access-control-registry/AccessControlRegistry.sol:AccessControlRegistry", + "label": "adminRole", + "offset": 0, + "slot": "1", + "type": "t_bytes32" + } + ], + "numberOfBytes": "64" + } + } + } +} diff --git a/packages/airnode-protocol/deployments/lightlink-goerli-testnet/AirnodeRrpV0.json b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/AirnodeRrpV0.json new file mode 100644 index 0000000000..ac80a516c1 --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/AirnodeRrpV0.json @@ -0,0 +1,1184 @@ +{ + "address": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "templateId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "CreatedTemplate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "string", + "name": "errorMessage", + "type": "string" + } + ], + "name": "FailedRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "FulfilledRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "withdrawalRequestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "FulfilledWithdrawal", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "requesterRequestCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "MadeFullRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "requesterRequestCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "templateId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "MadeTemplateRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "withdrawalRequestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + } + ], + "name": "RequestedWithdrawal", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "sponsorshipStatus", + "type": "bool" + } + ], + "name": "SetSponsorshipStatus", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "authorizers", + "type": "address[]" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + } + ], + "name": "checkAuthorizationStatus", + "outputs": [ + { + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "authorizers", + "type": "address[]" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32[]", + "name": "requestIds", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "endpointIds", + "type": "bytes32[]" + }, + { + "internalType": "address[]", + "name": "sponsors", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "requesters", + "type": "address[]" + } + ], + "name": "checkAuthorizationStatuses", + "outputs": [ + { + "internalType": "bool[]", + "name": "statuses", + "type": "bool[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "createTemplate", + "outputs": [ + { + "internalType": "bytes32", + "name": "templateId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "internalType": "string", + "name": "errorMessage", + "type": "string" + } + ], + "name": "fail", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "fulfill", + "outputs": [ + { + "internalType": "bool", + "name": "callSuccess", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRequestId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "address", + "name": "sponsor", + "type": "address" + } + ], + "name": "fulfillWithdrawal", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[]", + "name": "templateIds", + "type": "bytes32[]" + } + ], + "name": "getTemplates", + "outputs": [ + { + "internalType": "address[]", + "name": "airnodes", + "type": "address[]" + }, + { + "internalType": "bytes32[]", + "name": "endpointIds", + "type": "bytes32[]" + }, + { + "internalType": "bytes[]", + "name": "parameters", + "type": "bytes[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + }, + { + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "makeFullRequest", + "outputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "templateId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + }, + { + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "makeTemplateRequest", + "outputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + } + ], + "name": "requestIsAwaitingFulfillment", + "outputs": [ + { + "internalType": "bool", + "name": "isAwaitingFulfillment", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + } + ], + "name": "requestWithdrawal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "requesterToRequestCountPlusOne", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bool", + "name": "sponsorshipStatus", + "type": "bool" + } + ], + "name": "setSponsorshipStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "sponsorToRequesterToSponsorshipStatus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "sponsorToWithdrawalRequestCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "templates", + "outputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x31ef8f921d16e4398ad3202408b3991f347badcea82608561e7c528b0f0c2ce5", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xc97965EbD0f2123Cc31BEc63E18A8Ce9Ef6a1e7e", + "contractAddress": "0x0000000000000000000000000000000000000000", + "transactionIndex": 0, + "gasUsed": "2228742", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x533941a6bb30d9bb6d2e2925f475e18c3a95a5097808615a93bf957a284b056c", + "transactionHash": "0x31ef8f921d16e4398ad3202408b3991f347badcea82608561e7c528b0f0c2ce5", + "logs": [], + "blockNumber": 56898246, + "cumulativeGasUsed": "2228742", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "d8591a026515856ab7bc7dc284bf2fbe", + "metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"templateId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"CreatedTemplate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"errorMessage\",\"type\":\"string\"}],\"name\":\"FailedRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FulfilledRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"withdrawalRequestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FulfilledWithdrawal\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requesterRequestCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"MadeFullRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requesterRequestCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"templateId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"MadeTemplateRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"withdrawalRequestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"}],\"name\":\"RequestedWithdrawal\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sponsorshipStatus\",\"type\":\"bool\"}],\"name\":\"SetSponsorshipStatus\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"authorizers\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"name\":\"checkAuthorizationStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"authorizers\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"requestIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"endpointIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"sponsors\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"requesters\",\"type\":\"address[]\"}],\"name\":\"checkAuthorizationStatuses\",\"outputs\":[{\"internalType\":\"bool[]\",\"name\":\"statuses\",\"type\":\"bool[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"createTemplate\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"templateId\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"errorMessage\",\"type\":\"string\"}],\"name\":\"fail\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"callSuccess\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRequestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"}],\"name\":\"fulfillWithdrawal\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"templateIds\",\"type\":\"bytes32[]\"}],\"name\":\"getTemplates\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"airnodes\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"endpointIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes[]\",\"name\":\"parameters\",\"type\":\"bytes[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"makeFullRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"templateId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"makeTemplateRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"requestIsAwaitingFulfillment\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isAwaitingFulfillment\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"}],\"name\":\"requestWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"requesterToRequestCountPlusOne\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"sponsorshipStatus\",\"type\":\"bool\"}],\"name\":\"setSponsorshipStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"sponsorToRequesterToSponsorshipStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"sponsorToWithdrawalRequestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"templates\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"checkAuthorizationStatus(address[],address,bytes32,bytes32,address,address)\":{\"details\":\"This method is meant to be called off-chain, statically by the Airnode to decide if it should respond to a request. The requester can also call it, yet this function returning true should not be taken as a guarantee of the subsequent request being fulfilled. It is enough for only one of the authorizer contracts to return true for the request to be authorized.\",\"params\":{\"airnode\":\"Airnode address\",\"authorizers\":\"Authorizer contract addresses\",\"endpointId\":\"Endpoint ID\",\"requestId\":\"Request ID\",\"requester\":\"Requester address\",\"sponsor\":\"Sponsor address\"},\"returns\":{\"status\":\"Authorization status of the request\"}},\"checkAuthorizationStatuses(address[],address,bytes32[],bytes32[],address[],address[])\":{\"params\":{\"airnode\":\"Airnode address\",\"authorizers\":\"Authorizer contract addresses\",\"endpointIds\":\"Endpoint IDs\",\"requestIds\":\"Request IDs\",\"requesters\":\"Requester addresses\",\"sponsors\":\"Sponsor addresses\"},\"returns\":{\"statuses\":\"Authorization statuses of the request\"}},\"createTemplate(address,bytes32,bytes)\":{\"details\":\"A specific set of request parameters will always have the same template ID. This means a few things: (1) You can compute the expected ID of a template before creating it, (2) Creating a new template with the same parameters will overwrite the old one and return the same ID, (3) After you query a template with its ID, you can verify its integrity by applying the hash and comparing the result with the ID.\",\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID (allowed to be `bytes32(0)`)\",\"parameters\":\"Static request parameters (i.e., parameters that will not change between requests, unlike the dynamic parameters determined at request-time)\"},\"returns\":{\"templateId\":\"Request template ID\"}},\"fail(bytes32,address,address,bytes4,string)\":{\"details\":\"Airnode should fall back to this if a request cannot be fulfilled because static call to `fulfill()` returns `false` for `callSuccess`\",\"params\":{\"airnode\":\"Airnode address\",\"errorMessage\":\"A message that explains why the request has failed\",\"fulfillAddress\":\"Address that will be called to fulfill\",\"fulfillFunctionId\":\"Signature of the function that will be called to fulfill\",\"requestId\":\"Request ID\"}},\"fulfill(bytes32,address,address,bytes4,bytes,bytes)\":{\"details\":\"The data is ABI-encoded as a `bytes` type, with its format depending on the request specifications. This will not revert depending on the external call. However, it will return `false` if the external call reverts or if there is no function with a matching signature at `fulfillAddress`. On the other hand, it will return `true` if the external call returns successfully or if there is no contract deployed at `fulfillAddress`. If `callSuccess` is `false`, `callData` can be decoded to retrieve the revert string. This function emits its event after an untrusted low-level call, meaning that the order of these events within the transaction should not be taken seriously, yet the content will be sound.\",\"params\":{\"airnode\":\"Airnode address\",\"data\":\"Fulfillment data\",\"fulfillAddress\":\"Address that will be called to fulfill\",\"fulfillFunctionId\":\"Signature of the function that will be called to fulfill\",\"requestId\":\"Request ID\"},\"returns\":{\"callData\":\"Data returned by the fulfillment call (if there is any)\",\"callSuccess\":\"If the fulfillment call succeeded\"}},\"fulfillWithdrawal(bytes32,address,address)\":{\"details\":\"The Airnode sends the funds to the sponsor through this method to emit an event that indicates that the withdrawal request has been fulfilled\",\"params\":{\"airnode\":\"Airnode address\",\"sponsor\":\"Sponsor address\",\"withdrawalRequestId\":\"Withdrawal request ID\"}},\"getTemplates(bytes32[])\":{\"details\":\"Does not revert if the templates being indexed do not exist\",\"params\":{\"templateIds\":\"Request template IDs\"},\"returns\":{\"airnodes\":\"Array of Airnode addresses\",\"endpointIds\":\"Array of endpoint IDs\",\"parameters\":\"Array of request parameters\"}},\"makeFullRequest(address,bytes32,address,address,address,bytes4,bytes)\":{\"details\":\"`fulfillAddress` is not allowed to be the address of this contract. This is not actually needed to protect users that use the protocol as intended, but it is done for good measure.\",\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID (allowed to be `bytes32(0)`)\",\"fulfillAddress\":\"Address that will be called to fulfill\",\"fulfillFunctionId\":\"Signature of the function that will be called to fulfill\",\"parameters\":\"All request parameters\",\"sponsor\":\"Sponsor address\",\"sponsorWallet\":\"Sponsor wallet that is requested to fulfill the request\"},\"returns\":{\"requestId\":\"Request ID\"}},\"makeTemplateRequest(bytes32,address,address,address,bytes4,bytes)\":{\"details\":\"`fulfillAddress` is not allowed to be the address of this contract. This is not actually needed to protect users that use the protocol as intended, but it is done for good measure.\",\"params\":{\"fulfillAddress\":\"Address that will be called to fulfill\",\"fulfillFunctionId\":\"Signature of the function that will be called to fulfill\",\"parameters\":\"Parameters provided by the requester in addition to the parameters in the template\",\"sponsor\":\"Sponsor address\",\"sponsorWallet\":\"Sponsor wallet that is requested to fulfill the request\",\"templateId\":\"Template ID\"},\"returns\":{\"requestId\":\"Request ID\"}},\"requestIsAwaitingFulfillment(bytes32)\":{\"details\":\"If a requester has made a request, received a request ID but did not hear back, it can call this method to check if the Airnode has called back `fail()` instead.\",\"params\":{\"requestId\":\"Request ID\"},\"returns\":{\"isAwaitingFulfillment\":\"If the request is awaiting fulfillment (i.e., `true` if `fulfill()` or `fail()` is not called back yet, `false` otherwise)\"}},\"requestWithdrawal(address,address)\":{\"details\":\"We do not need to use the withdrawal request parameters in the request ID hash to validate them at the node-side because all of the parameters are used during fulfillment and will get validated on-chain. The first withdrawal request a sponsor will make will cost slightly higher gas than the rest due to how the request counter is implemented.\",\"params\":{\"airnode\":\"Airnode address\",\"sponsorWallet\":\"Sponsor wallet that the withdrawal is requested from\"}},\"setSponsorshipStatus(address,bool)\":{\"details\":\"This is not Airnode-specific, i.e., the sponsor allows the requester's requests to be fulfilled through its sponsor wallets across all Airnodes\",\"params\":{\"requester\":\"Requester address\",\"sponsorshipStatus\":\"Sponsorship status\"}}},\"stateVariables\":{\"requestIdToFulfillmentParameters\":{\"details\":\"Hash of expected fulfillment parameters are kept to verify that the fulfillment will be done with the correct parameters. This value is also used to check if the fulfillment for the particular request is expected, i.e., if there are recorded fulfillment parameters.\"},\"requesterToRequestCountPlusOne\":{\"details\":\"Can be used to calculate the ID of the next request the requester will make\"}},\"title\":\"Contract that implements the Airnode request\\u2013response protocol (RRP)\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"checkAuthorizationStatus(address[],address,bytes32,bytes32,address,address)\":{\"notice\":\"Uses the authorizer contracts of an Airnode to decide if a request is authorized. Once an Airnode receives a request, it calls this method to determine if it should respond. Similarly, third parties can use this method to determine if a particular request would be authorized.\"},\"checkAuthorizationStatuses(address[],address,bytes32[],bytes32[],address[],address[])\":{\"notice\":\"A convenience function to make multiple authorization status checks with a single call\"},\"createTemplate(address,bytes32,bytes)\":{\"notice\":\"Creates a request template with the given parameters, addressable by the ID it returns\"},\"fail(bytes32,address,address,bytes4,string)\":{\"notice\":\"Called by Airnode if the request cannot be fulfilled\"},\"fulfill(bytes32,address,address,bytes4,bytes,bytes)\":{\"notice\":\"Called by Airnode to fulfill the request (template or full)\"},\"fulfillWithdrawal(bytes32,address,address)\":{\"notice\":\"Called by the Airnode using the sponsor wallet to fulfill the withdrawal request made by the sponsor\"},\"getTemplates(bytes32[])\":{\"notice\":\"A convenience method to retrieve multiple templates with a single call\"},\"makeFullRequest(address,bytes32,address,address,address,bytes4,bytes)\":{\"notice\":\"Called by the requester to make a full request, which provides all of its parameters as arguments and does not refer to a template\"},\"makeTemplateRequest(bytes32,address,address,address,bytes4,bytes)\":{\"notice\":\"Called by the requester to make a request that refers to a template for the Airnode address, endpoint ID and parameters\"},\"requestIsAwaitingFulfillment(bytes32)\":{\"notice\":\"Called to check if the request with the ID is made but not fulfilled/failed yet\"},\"requestWithdrawal(address,address)\":{\"notice\":\"Called by a sponsor to create a request for the Airnode to send the funds kept in the respective sponsor wallet to the sponsor\"},\"requesterToRequestCountPlusOne(address)\":{\"notice\":\"Called to get the request count of the requester plus one\"},\"setSponsorshipStatus(address,bool)\":{\"notice\":\"Called by the sponsor to set the sponsorship status of a requester, i.e., allow or disallow a requester to make requests that will be fulfilled by the sponsor wallet\"},\"sponsorToRequesterToSponsorshipStatus(address,address)\":{\"notice\":\"Called to get the sponsorship status for a sponsor\\u2013requester pair\"},\"sponsorToWithdrawalRequestCount(address)\":{\"notice\":\"Called to get the withdrawal request count of the sponsor\"},\"templates(bytes32)\":{\"notice\":\"Called to get a template\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/rrp/AirnodeRrpV0.sol\":\"AirnodeRrpV0\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s;\\n uint8 v;\\n assembly {\\n s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\\n v := add(shr(255, vs), 27)\\n }\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xe9e291de7ffe06e66503c6700b1bb84ff6e0989cbb974653628d8994e7c97f03\",\"license\":\"MIT\"},\"contracts/authorizers/interfaces/IAuthorizerV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IAuthorizerV0 {\\n function isAuthorizedV0(\\n bytes32 requestId,\\n address airnode,\\n bytes32 endpointId,\\n address sponsor,\\n address requester\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xa38872f5dead4dfc0c8075c245c10197df1ace09415f2e0d5b46bc8511cc3f6d\",\"license\":\"MIT\"},\"contracts/rrp/AirnodeRrpV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"./AuthorizationUtilsV0.sol\\\";\\nimport \\\"./TemplateUtilsV0.sol\\\";\\nimport \\\"./WithdrawalUtilsV0.sol\\\";\\nimport \\\"./interfaces/IAirnodeRrpV0.sol\\\";\\n\\n/// @title Contract that implements the Airnode request\\u2013response protocol (RRP)\\ncontract AirnodeRrpV0 is\\n AuthorizationUtilsV0,\\n TemplateUtilsV0,\\n WithdrawalUtilsV0,\\n IAirnodeRrpV0\\n{\\n using ECDSA for bytes32;\\n\\n /// @notice Called to get the sponsorship status for a sponsor\\u2013requester\\n /// pair\\n mapping(address => mapping(address => bool))\\n public\\n override sponsorToRequesterToSponsorshipStatus;\\n\\n /// @notice Called to get the request count of the requester plus one\\n /// @dev Can be used to calculate the ID of the next request the requester\\n /// will make\\n mapping(address => uint256) public override requesterToRequestCountPlusOne;\\n\\n /// @dev Hash of expected fulfillment parameters are kept to verify that\\n /// the fulfillment will be done with the correct parameters. This value is\\n /// also used to check if the fulfillment for the particular request is\\n /// expected, i.e., if there are recorded fulfillment parameters.\\n mapping(bytes32 => bytes32) private requestIdToFulfillmentParameters;\\n\\n /// @notice Called by the sponsor to set the sponsorship status of a\\n /// requester, i.e., allow or disallow a requester to make requests that\\n /// will be fulfilled by the sponsor wallet\\n /// @dev This is not Airnode-specific, i.e., the sponsor allows the\\n /// requester's requests to be fulfilled through its sponsor wallets across\\n /// all Airnodes\\n /// @param requester Requester address\\n /// @param sponsorshipStatus Sponsorship status\\n function setSponsorshipStatus(address requester, bool sponsorshipStatus)\\n external\\n override\\n {\\n // Initialize the requester request count for consistent request gas\\n // cost\\n if (requesterToRequestCountPlusOne[requester] == 0) {\\n requesterToRequestCountPlusOne[requester] = 1;\\n }\\n sponsorToRequesterToSponsorshipStatus[msg.sender][\\n requester\\n ] = sponsorshipStatus;\\n emit SetSponsorshipStatus(msg.sender, requester, sponsorshipStatus);\\n }\\n\\n /// @notice Called by the requester to make a request that refers to a\\n /// template for the Airnode address, endpoint ID and parameters\\n /// @dev `fulfillAddress` is not allowed to be the address of this\\n /// contract. This is not actually needed to protect users that use the\\n /// protocol as intended, but it is done for good measure.\\n /// @param templateId Template ID\\n /// @param sponsor Sponsor address\\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill the\\n /// request\\n /// @param fulfillAddress Address that will be called to fulfill\\n /// @param fulfillFunctionId Signature of the function that will be called\\n /// to fulfill\\n /// @param parameters Parameters provided by the requester in addition to\\n /// the parameters in the template\\n /// @return requestId Request ID\\n function makeTemplateRequest(\\n bytes32 templateId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata parameters\\n ) external override returns (bytes32 requestId) {\\n address airnode = templates[templateId].airnode;\\n // If the Airnode address of the template is zero the template does not\\n // exist because template creation does not allow zero Airnode address\\n require(airnode != address(0), \\\"Template does not exist\\\");\\n require(fulfillAddress != address(this), \\\"Fulfill address AirnodeRrp\\\");\\n require(\\n sponsorToRequesterToSponsorshipStatus[sponsor][msg.sender],\\n \\\"Requester not sponsored\\\"\\n );\\n uint256 requesterRequestCount = requesterToRequestCountPlusOne[\\n msg.sender\\n ];\\n requestId = keccak256(\\n abi.encodePacked(\\n block.chainid,\\n address(this),\\n msg.sender,\\n requesterRequestCount,\\n templateId,\\n sponsor,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId,\\n parameters\\n )\\n );\\n requestIdToFulfillmentParameters[requestId] = keccak256(\\n abi.encodePacked(\\n airnode,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId\\n )\\n );\\n requesterToRequestCountPlusOne[msg.sender]++;\\n emit MadeTemplateRequest(\\n airnode,\\n requestId,\\n requesterRequestCount,\\n block.chainid,\\n msg.sender,\\n templateId,\\n sponsor,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId,\\n parameters\\n );\\n }\\n\\n /// @notice Called by the requester to make a full request, which provides\\n /// all of its parameters as arguments and does not refer to a template\\n /// @dev `fulfillAddress` is not allowed to be the address of this\\n /// contract. This is not actually needed to protect users that use the\\n /// protocol as intended, but it is done for good measure.\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param sponsor Sponsor address\\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill\\n /// the request\\n /// @param fulfillAddress Address that will be called to fulfill\\n /// @param fulfillFunctionId Signature of the function that will be called\\n /// to fulfill\\n /// @param parameters All request parameters\\n /// @return requestId Request ID\\n function makeFullRequest(\\n address airnode,\\n bytes32 endpointId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata parameters\\n ) external override returns (bytes32 requestId) {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n require(fulfillAddress != address(this), \\\"Fulfill address AirnodeRrp\\\");\\n require(\\n sponsorToRequesterToSponsorshipStatus[sponsor][msg.sender],\\n \\\"Requester not sponsored\\\"\\n );\\n uint256 requesterRequestCount = requesterToRequestCountPlusOne[\\n msg.sender\\n ];\\n requestId = keccak256(\\n abi.encodePacked(\\n block.chainid,\\n address(this),\\n msg.sender,\\n requesterRequestCount,\\n airnode,\\n endpointId,\\n sponsor,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId,\\n parameters\\n )\\n );\\n requestIdToFulfillmentParameters[requestId] = keccak256(\\n abi.encodePacked(\\n airnode,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId\\n )\\n );\\n requesterToRequestCountPlusOne[msg.sender]++;\\n emit MadeFullRequest(\\n airnode,\\n requestId,\\n requesterRequestCount,\\n block.chainid,\\n msg.sender,\\n endpointId,\\n sponsor,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId,\\n parameters\\n );\\n }\\n\\n /// @notice Called by Airnode to fulfill the request (template or full)\\n /// @dev The data is ABI-encoded as a `bytes` type, with its format\\n /// depending on the request specifications.\\n /// This will not revert depending on the external call. However, it will\\n /// return `false` if the external call reverts or if there is no function\\n /// with a matching signature at `fulfillAddress`. On the other hand, it\\n /// will return `true` if the external call returns successfully or if\\n /// there is no contract deployed at `fulfillAddress`.\\n /// If `callSuccess` is `false`, `callData` can be decoded to retrieve the\\n /// revert string.\\n /// This function emits its event after an untrusted low-level call,\\n /// meaning that the order of these events within the transaction should\\n /// not be taken seriously, yet the content will be sound.\\n /// @param requestId Request ID\\n /// @param airnode Airnode address\\n /// @param data Fulfillment data\\n /// @param fulfillAddress Address that will be called to fulfill\\n /// @param fulfillFunctionId Signature of the function that will be called\\n /// to fulfill\\n /// @return callSuccess If the fulfillment call succeeded\\n /// @return callData Data returned by the fulfillment call (if there is\\n /// any)\\n function fulfill(\\n bytes32 requestId,\\n address airnode,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata data,\\n bytes calldata signature\\n ) external override returns (bool callSuccess, bytes memory callData) {\\n require(\\n keccak256(\\n abi.encodePacked(\\n airnode,\\n msg.sender,\\n fulfillAddress,\\n fulfillFunctionId\\n )\\n ) == requestIdToFulfillmentParameters[requestId],\\n \\\"Invalid request fulfillment\\\"\\n );\\n require(\\n (\\n keccak256(abi.encodePacked(requestId, data))\\n .toEthSignedMessageHash()\\n ).recover(signature) == airnode,\\n \\\"Invalid signature\\\"\\n );\\n delete requestIdToFulfillmentParameters[requestId];\\n (callSuccess, callData) = fulfillAddress.call( // solhint-disable-line avoid-low-level-calls\\n abi.encodeWithSelector(fulfillFunctionId, requestId, data)\\n );\\n if (callSuccess) {\\n emit FulfilledRequest(airnode, requestId, data);\\n } else {\\n // We do not bubble up the revert string from `callData`\\n emit FailedRequest(\\n airnode,\\n requestId,\\n \\\"Fulfillment failed unexpectedly\\\"\\n );\\n }\\n }\\n\\n /// @notice Called by Airnode if the request cannot be fulfilled\\n /// @dev Airnode should fall back to this if a request cannot be fulfilled\\n /// because static call to `fulfill()` returns `false` for `callSuccess`\\n /// @param requestId Request ID\\n /// @param airnode Airnode address\\n /// @param fulfillAddress Address that will be called to fulfill\\n /// @param fulfillFunctionId Signature of the function that will be called\\n /// to fulfill\\n /// @param errorMessage A message that explains why the request has failed\\n function fail(\\n bytes32 requestId,\\n address airnode,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n string calldata errorMessage\\n ) external override {\\n require(\\n keccak256(\\n abi.encodePacked(\\n airnode,\\n msg.sender,\\n fulfillAddress,\\n fulfillFunctionId\\n )\\n ) == requestIdToFulfillmentParameters[requestId],\\n \\\"Invalid request fulfillment\\\"\\n );\\n delete requestIdToFulfillmentParameters[requestId];\\n emit FailedRequest(airnode, requestId, errorMessage);\\n }\\n\\n /// @notice Called to check if the request with the ID is made but not\\n /// fulfilled/failed yet\\n /// @dev If a requester has made a request, received a request ID but did\\n /// not hear back, it can call this method to check if the Airnode has\\n /// called back `fail()` instead.\\n /// @param requestId Request ID\\n /// @return isAwaitingFulfillment If the request is awaiting fulfillment\\n /// (i.e., `true` if `fulfill()` or `fail()` is not called back yet,\\n /// `false` otherwise)\\n function requestIsAwaitingFulfillment(bytes32 requestId)\\n external\\n view\\n override\\n returns (bool isAwaitingFulfillment)\\n {\\n isAwaitingFulfillment =\\n requestIdToFulfillmentParameters[requestId] != bytes32(0);\\n }\\n}\\n\",\"keccak256\":\"0x7b770788b2ca3661f9617b887fef62aff0d795cd32e15dc61e05ada5637a1093\",\"license\":\"MIT\"},\"contracts/rrp/AuthorizationUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/IAuthorizationUtilsV0.sol\\\";\\nimport \\\"../authorizers/interfaces/IAuthorizerV0.sol\\\";\\n\\n/// @title Contract that implements authorization checks\\ncontract AuthorizationUtilsV0 is IAuthorizationUtilsV0 {\\n /// @notice Uses the authorizer contracts of an Airnode to decide if a\\n /// request is authorized. Once an Airnode receives a request, it calls\\n /// this method to determine if it should respond. Similarly, third parties\\n /// can use this method to determine if a particular request would be\\n /// authorized.\\n /// @dev This method is meant to be called off-chain, statically by the\\n /// Airnode to decide if it should respond to a request. The requester can\\n /// also call it, yet this function returning true should not be taken as a\\n /// guarantee of the subsequent request being fulfilled.\\n /// It is enough for only one of the authorizer contracts to return true\\n /// for the request to be authorized.\\n /// @param authorizers Authorizer contract addresses\\n /// @param airnode Airnode address\\n /// @param requestId Request ID\\n /// @param endpointId Endpoint ID\\n /// @param sponsor Sponsor address\\n /// @param requester Requester address\\n /// @return status Authorization status of the request\\n function checkAuthorizationStatus(\\n address[] calldata authorizers,\\n address airnode,\\n bytes32 requestId,\\n bytes32 endpointId,\\n address sponsor,\\n address requester\\n ) public view override returns (bool status) {\\n for (uint256 ind = 0; ind < authorizers.length; ind++) {\\n IAuthorizerV0 authorizer = IAuthorizerV0(authorizers[ind]);\\n if (\\n authorizer.isAuthorizedV0(\\n requestId,\\n airnode,\\n endpointId,\\n sponsor,\\n requester\\n )\\n ) {\\n return true;\\n }\\n }\\n return false;\\n }\\n\\n /// @notice A convenience function to make multiple authorization status\\n /// checks with a single call\\n /// @param authorizers Authorizer contract addresses\\n /// @param airnode Airnode address\\n /// @param requestIds Request IDs\\n /// @param endpointIds Endpoint IDs\\n /// @param sponsors Sponsor addresses\\n /// @param requesters Requester addresses\\n /// @return statuses Authorization statuses of the request\\n function checkAuthorizationStatuses(\\n address[] calldata authorizers,\\n address airnode,\\n bytes32[] calldata requestIds,\\n bytes32[] calldata endpointIds,\\n address[] calldata sponsors,\\n address[] calldata requesters\\n ) external view override returns (bool[] memory statuses) {\\n require(\\n requestIds.length == endpointIds.length &&\\n requestIds.length == sponsors.length &&\\n requestIds.length == requesters.length,\\n \\\"Unequal parameter lengths\\\"\\n );\\n statuses = new bool[](requestIds.length);\\n for (uint256 ind = 0; ind < requestIds.length; ind++) {\\n statuses[ind] = checkAuthorizationStatus(\\n authorizers,\\n airnode,\\n requestIds[ind],\\n endpointIds[ind],\\n sponsors[ind],\\n requesters[ind]\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa3419ee8a4146a7716355e835102700bfdd12928ab83790d368a344e7819a502\",\"license\":\"MIT\"},\"contracts/rrp/TemplateUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/ITemplateUtilsV0.sol\\\";\\n\\n/// @title Contract that implements request templates\\ncontract TemplateUtilsV0 is ITemplateUtilsV0 {\\n struct Template {\\n address airnode;\\n bytes32 endpointId;\\n bytes parameters;\\n }\\n\\n /// @notice Called to get a template\\n mapping(bytes32 => Template) public override templates;\\n\\n /// @notice Creates a request template with the given parameters,\\n /// addressable by the ID it returns\\n /// @dev A specific set of request parameters will always have the same\\n /// template ID. This means a few things: (1) You can compute the expected\\n /// ID of a template before creating it, (2) Creating a new template with\\n /// the same parameters will overwrite the old one and return the same ID,\\n /// (3) After you query a template with its ID, you can verify its\\n /// integrity by applying the hash and comparing the result with the ID.\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param parameters Static request parameters (i.e., parameters that will\\n /// not change between requests, unlike the dynamic parameters determined\\n /// at request-time)\\n /// @return templateId Request template ID\\n function createTemplate(\\n address airnode,\\n bytes32 endpointId,\\n bytes calldata parameters\\n ) external override returns (bytes32 templateId) {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n templateId = keccak256(\\n abi.encodePacked(airnode, endpointId, parameters)\\n );\\n templates[templateId] = Template({\\n airnode: airnode,\\n endpointId: endpointId,\\n parameters: parameters\\n });\\n emit CreatedTemplate(templateId, airnode, endpointId, parameters);\\n }\\n\\n /// @notice A convenience method to retrieve multiple templates with a\\n /// single call\\n /// @dev Does not revert if the templates being indexed do not exist\\n /// @param templateIds Request template IDs\\n /// @return airnodes Array of Airnode addresses\\n /// @return endpointIds Array of endpoint IDs\\n /// @return parameters Array of request parameters\\n function getTemplates(bytes32[] calldata templateIds)\\n external\\n view\\n override\\n returns (\\n address[] memory airnodes,\\n bytes32[] memory endpointIds,\\n bytes[] memory parameters\\n )\\n {\\n airnodes = new address[](templateIds.length);\\n endpointIds = new bytes32[](templateIds.length);\\n parameters = new bytes[](templateIds.length);\\n for (uint256 ind = 0; ind < templateIds.length; ind++) {\\n Template storage template = templates[templateIds[ind]];\\n airnodes[ind] = template.airnode;\\n endpointIds[ind] = template.endpointId;\\n parameters[ind] = template.parameters;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x6196d12fd828783a299819b75ab3cdf10e84d39b8d8419be28b613e10a7a7602\",\"license\":\"MIT\"},\"contracts/rrp/WithdrawalUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/IWithdrawalUtilsV0.sol\\\";\\n\\n/// @title Contract that implements logic for withdrawals from sponsor wallets\\ncontract WithdrawalUtilsV0 is IWithdrawalUtilsV0 {\\n /// @notice Called to get the withdrawal request count of the sponsor\\n /// @dev Can be used to calculate the ID of the next withdrawal request the\\n /// sponsor will make\\n mapping(address => uint256) public override sponsorToWithdrawalRequestCount;\\n\\n /// @dev Hash of expected fulfillment parameters are kept to verify that\\n /// the fulfillment will be done with the correct parameters\\n mapping(bytes32 => bytes32) private withdrawalRequestIdToParameters;\\n\\n /// @notice Called by a sponsor to create a request for the Airnode to send\\n /// the funds kept in the respective sponsor wallet to the sponsor\\n /// @dev We do not need to use the withdrawal request parameters in the\\n /// request ID hash to validate them at the node-side because all of the\\n /// parameters are used during fulfillment and will get validated on-chain.\\n /// The first withdrawal request a sponsor will make will cost slightly\\n /// higher gas than the rest due to how the request counter is implemented.\\n /// @param airnode Airnode address\\n /// @param sponsorWallet Sponsor wallet that the withdrawal is requested\\n /// from\\n function requestWithdrawal(address airnode, address sponsorWallet)\\n external\\n override\\n {\\n bytes32 withdrawalRequestId = keccak256(\\n abi.encodePacked(\\n block.chainid,\\n address(this),\\n msg.sender,\\n ++sponsorToWithdrawalRequestCount[msg.sender]\\n )\\n );\\n withdrawalRequestIdToParameters[withdrawalRequestId] = keccak256(\\n abi.encodePacked(airnode, msg.sender, sponsorWallet)\\n );\\n emit RequestedWithdrawal(\\n airnode,\\n msg.sender,\\n withdrawalRequestId,\\n sponsorWallet\\n );\\n }\\n\\n /// @notice Called by the Airnode using the sponsor wallet to fulfill the\\n /// withdrawal request made by the sponsor\\n /// @dev The Airnode sends the funds to the sponsor through this method\\n /// to emit an event that indicates that the withdrawal request has been\\n /// fulfilled\\n /// @param withdrawalRequestId Withdrawal request ID\\n /// @param airnode Airnode address\\n /// @param sponsor Sponsor address\\n function fulfillWithdrawal(\\n bytes32 withdrawalRequestId,\\n address airnode,\\n address sponsor\\n ) external payable override {\\n require(\\n withdrawalRequestIdToParameters[withdrawalRequestId] ==\\n keccak256(abi.encodePacked(airnode, sponsor, msg.sender)),\\n \\\"Invalid withdrawal fulfillment\\\"\\n );\\n delete withdrawalRequestIdToParameters[withdrawalRequestId];\\n emit FulfilledWithdrawal(\\n airnode,\\n sponsor,\\n withdrawalRequestId,\\n msg.sender,\\n msg.value\\n );\\n (bool success, ) = sponsor.call{value: msg.value}(\\\"\\\"); // solhint-disable-line avoid-low-level-calls\\n require(success, \\\"Transfer failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0x45f937dd2b57942913d4ab1c0e08356fd57cd3d2cca013604adbb8de0e0c898b\",\"license\":\"MIT\"},\"contracts/rrp/interfaces/IAirnodeRrpV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAuthorizationUtilsV0.sol\\\";\\nimport \\\"./ITemplateUtilsV0.sol\\\";\\nimport \\\"./IWithdrawalUtilsV0.sol\\\";\\n\\ninterface IAirnodeRrpV0 is\\n IAuthorizationUtilsV0,\\n ITemplateUtilsV0,\\n IWithdrawalUtilsV0\\n{\\n event SetSponsorshipStatus(\\n address indexed sponsor,\\n address indexed requester,\\n bool sponsorshipStatus\\n );\\n\\n event MadeTemplateRequest(\\n address indexed airnode,\\n bytes32 indexed requestId,\\n uint256 requesterRequestCount,\\n uint256 chainId,\\n address requester,\\n bytes32 templateId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes parameters\\n );\\n\\n event MadeFullRequest(\\n address indexed airnode,\\n bytes32 indexed requestId,\\n uint256 requesterRequestCount,\\n uint256 chainId,\\n address requester,\\n bytes32 endpointId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes parameters\\n );\\n\\n event FulfilledRequest(\\n address indexed airnode,\\n bytes32 indexed requestId,\\n bytes data\\n );\\n\\n event FailedRequest(\\n address indexed airnode,\\n bytes32 indexed requestId,\\n string errorMessage\\n );\\n\\n function setSponsorshipStatus(address requester, bool sponsorshipStatus)\\n external;\\n\\n function makeTemplateRequest(\\n bytes32 templateId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata parameters\\n ) external returns (bytes32 requestId);\\n\\n function makeFullRequest(\\n address airnode,\\n bytes32 endpointId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata parameters\\n ) external returns (bytes32 requestId);\\n\\n function fulfill(\\n bytes32 requestId,\\n address airnode,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata data,\\n bytes calldata signature\\n ) external returns (bool callSuccess, bytes memory callData);\\n\\n function fail(\\n bytes32 requestId,\\n address airnode,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n string calldata errorMessage\\n ) external;\\n\\n function sponsorToRequesterToSponsorshipStatus(\\n address sponsor,\\n address requester\\n ) external view returns (bool sponsorshipStatus);\\n\\n function requesterToRequestCountPlusOne(address requester)\\n external\\n view\\n returns (uint256 requestCountPlusOne);\\n\\n function requestIsAwaitingFulfillment(bytes32 requestId)\\n external\\n view\\n returns (bool isAwaitingFulfillment);\\n}\\n\",\"keccak256\":\"0x5306571db1377e8c9dd8cb6e6c7a8deaa2d8ec540e7b2b229e9db5aa5da21277\",\"license\":\"MIT\"},\"contracts/rrp/interfaces/IAuthorizationUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IAuthorizationUtilsV0 {\\n function checkAuthorizationStatus(\\n address[] calldata authorizers,\\n address airnode,\\n bytes32 requestId,\\n bytes32 endpointId,\\n address sponsor,\\n address requester\\n ) external view returns (bool status);\\n\\n function checkAuthorizationStatuses(\\n address[] calldata authorizers,\\n address airnode,\\n bytes32[] calldata requestIds,\\n bytes32[] calldata endpointIds,\\n address[] calldata sponsors,\\n address[] calldata requesters\\n ) external view returns (bool[] memory statuses);\\n}\\n\",\"keccak256\":\"0x597a40e9911628f6bc1d845c9ebe7c345833e8814caa5ce02a8597d3b4ee7975\",\"license\":\"MIT\"},\"contracts/rrp/interfaces/ITemplateUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface ITemplateUtilsV0 {\\n event CreatedTemplate(\\n bytes32 indexed templateId,\\n address airnode,\\n bytes32 endpointId,\\n bytes parameters\\n );\\n\\n function createTemplate(\\n address airnode,\\n bytes32 endpointId,\\n bytes calldata parameters\\n ) external returns (bytes32 templateId);\\n\\n function getTemplates(bytes32[] calldata templateIds)\\n external\\n view\\n returns (\\n address[] memory airnodes,\\n bytes32[] memory endpointIds,\\n bytes[] memory parameters\\n );\\n\\n function templates(bytes32 templateId)\\n external\\n view\\n returns (\\n address airnode,\\n bytes32 endpointId,\\n bytes memory parameters\\n );\\n}\\n\",\"keccak256\":\"0x4212b264303a78b3c3ed0230cf23b7c3ca58bccec936eccd1d4924347b0fea47\",\"license\":\"MIT\"},\"contracts/rrp/interfaces/IWithdrawalUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IWithdrawalUtilsV0 {\\n event RequestedWithdrawal(\\n address indexed airnode,\\n address indexed sponsor,\\n bytes32 indexed withdrawalRequestId,\\n address sponsorWallet\\n );\\n\\n event FulfilledWithdrawal(\\n address indexed airnode,\\n address indexed sponsor,\\n bytes32 indexed withdrawalRequestId,\\n address sponsorWallet,\\n uint256 amount\\n );\\n\\n function requestWithdrawal(address airnode, address sponsorWallet) external;\\n\\n function fulfillWithdrawal(\\n bytes32 withdrawalRequestId,\\n address airnode,\\n address sponsor\\n ) external payable;\\n\\n function sponsorToWithdrawalRequestCount(address sponsor)\\n external\\n view\\n returns (uint256 withdrawalRequestCount);\\n}\\n\",\"keccak256\":\"0x732a3a2447150d8a8097042719ca1faf35e06cbfec364d1d6b17aae254cfd520\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5061274d806100206000396000f3fe6080604052600436106100f35760003560e01c806376428c9b1161008a578063acbe180011610059578063acbe1800146102f7578063addf027c14610317578063ca31d58614610337578063f8fa73a11461036457600080fd5b806376428c9b146102405780637e7166f31461026f5780638a33be011461029c578063a81e9f79146102bc57600080fd5b80633c7fe5e3116100c65780633c7fe5e3146101ae57806350743bb9146101c157806352e41f99146102005780636e6be03f1461022057600080fd5b80630a631576146100f85780631d414cbd146101305780631decbf181461015257806332393f2b14610180575b600080fd5b34801561010457600080fd5b50610118610113366004611bd0565b610391565b60405161012793929190611c41565b60405180910390f35b34801561013c57600080fd5b5061015061014b366004611c8e565b610446565b005b34801561015e57600080fd5b5061017261016d366004611d1b565b610566565b604051610127929190611dc6565b34801561018c57600080fd5b506101a061019b366004611de9565b6108d8565b604051908152602001610127565b6101506101bc366004611e43565b610a68565b3480156101cd57600080fd5b506101f06101dc366004611bd0565b600090815260056020526040902054151590565b6040519015158152602001610127565b34801561020c57600080fd5b5061015061021b366004611e7f565b610c15565b34801561022c57600080fd5b506101a061023b366004611efe565b610d30565b34801561024c57600080fd5b5061026061025b366004611fcf565b610fa4565b60405161012793929190612069565b34801561027b57600080fd5b506101a061028a366004612100565b60046020526000908152604090205481565b3480156102a857600080fd5b506101f06102b7366004612122565b6111ed565b3480156102c857600080fd5b506101f06102d7366004611c8e565b600360209081526000928352604080842090915290825290205460ff1681565b34801561030357600080fd5b506101a06103123660046121ab565b61130a565b34801561032357600080fd5b50610150610332366004612249565b611589565b34801561034357600080fd5b50610357610352366004612280565b61162f565b6040516101279190612384565b34801561037057600080fd5b506101a061037f366004612100565b60016020526000908152604090205481565b6000602081905290815260409020805460018201546002830180546001600160a01b039093169391926103c3906123ca565b80601f01602080910402602001604051908101604052809291908181526020018280546103ef906123ca565b801561043c5780601f106104115761010080835404028352916020019161043c565b820191906000526020600020905b81548152906001019060200180831161041f57829003601f168201915b5050505050905083565b336000818152600160205260408120805491924692309290859061046990612405565b91829055506040805160208101959095526bffffffffffffffffffffffff19606094851b8116918601919091529190921b166054830152606882015260880160408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606087811b82169385019390935233831b811660348501529185901b90911660488301529150605c0160408051808303601f19018152828252805160209182012060008581526002835292909220919091556001600160a01b03848116835283923392918716917fd48d52c7c6d0c940f3f8d07591e1800ef3a70daf79929a97ccd80b4494769fc7910160405180910390a4505050565b60008881526005602090815260408083205490516bffffffffffffffffffffffff1960608c811b82169483019490945233841b811660348301528a841b1660488201526001600160e01b03198916605c820152820160405160208183030381529060405280519060200120146106235760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e74000000000060448201526064015b60405180910390fd5b886001600160a01b03166106e585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516106df925061067f91508f908c908c9060200161243d565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b906117b0565b6001600160a01b03161461073b5760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e6174757265000000000000000000000000000000604482015260640161061a565b60008a81526005602052604080822091909155516001600160a01b03891690889061076e908d908a908a90602401612480565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516107c1919061249a565b6000604051808303816000865af19150503d80600081146107fe576040519150601f19603f3d011682016040523d82523d6000602084013e610803565b606091505b50909250905081156108585789896001600160a01b03167fc0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a888860405161084b9291906124b6565b60405180910390a36108cb565b89896001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc6040516108c2906020808252601f908201527f46756c66696c6c6d656e74206661696c656420756e65787065637465646c7900604082015260600190565b60405180910390a35b9850989650505050505050565b60006001600160a01b0385166109305760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b8484848460405160200161094794939291906124ca565b6040516020818303038152906040528051906020012090506040518060600160405280866001600160a01b0316815260200185815260200184848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509390945250508381526020818152604091829020845181547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178155848201516001820155918401518051929350610a1e9260028501929190910190611b37565b50905050807fba204bad31c4ec4b9b54164af94ae10c4e7312f22c0f9c065d6319c928ec9e7a86868686604051610a5894939291906124fd565b60405180910390a2949350505050565b6040516bffffffffffffffffffffffff19606084811b8216602084015283811b8216603484015233901b166048820152605c0160408051601f1981840301815291815281516020928301206000868152600290935291205414610b0d5760405162461bcd60e51b815260206004820152601e60248201527f496e76616c6964207769746864726177616c2066756c66696c6c6d656e740000604482015260640161061a565b6000838152600260209081526040808320929092558151338152349181019190915284916001600160a01b0380851692908616917fadb4840bbd5f924665ae7e0e0c83de5c0fb40a98c9b57dba53a6c978127a622e910160405180910390a46000816001600160a01b03163460405160006040518083038185875af1925050503d8060008114610bb9576040519150601f19603f3d011682016040523d82523d6000602084013e610bbe565b606091505b5050905080610c0f5760405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c65640000000000000000000000000000000000604482015260640161061a565b50505050565b6000868152600560209081526040918290205491516bffffffffffffffffffffffff19606089811b82169383019390935233831b8116603483015287831b1660488201526001600160e01b03198616605c820152016040516020818303038152906040528051906020012014610ccd5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e740000000000604482015260640161061a565b600560008781526020019081526020016000206000905585856001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc8484604051610d209291906124b6565b60405180910390a3505050505050565b60006001600160a01b038916610d885760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b6001600160a01b038516301415610de15760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038716600090815260036020908152604080832033845290915290205460ff16610e545760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d8d604051602001610ea59c9b9a99989796959493929190612530565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff1960608e811b8216938501939093528a831b8116603485015289831b1660488401526001600160e01b03198816605c84015293500160408051601f1981840301815291815281516020928301206000858152600584528281209190915533815260049092528120805491610f3e83612405565b9190505550818a6001600160a01b03167f3a52c462346de2e9436a3868970892956828a11b9c43da1ed43740b12e1125ae8346338e8e8e8e8e8e8e604051610f8f9a999897969594939291906125bf565b60405180910390a35098975050505050505050565b606080808367ffffffffffffffff811115610fc157610fc1612631565b604051908082528060200260200182016040528015610fea578160200160208202803683370190505b5092508367ffffffffffffffff81111561100657611006612631565b60405190808252806020026020018201604052801561102f578160200160208202803683370190505b5091508367ffffffffffffffff81111561104b5761104b612631565b60405190808252806020026020018201604052801561107e57816020015b60608152602001906001900390816110695790505b50905060005b848110156111e55760008060008888858181106110a3576110a3612647565b90506020020135815260200190815260200160002090508060000160009054906101000a90046001600160a01b03168583815181106110e4576110e4612647565b60200260200101906001600160a01b031690816001600160a01b031681525050806001015484838151811061111b5761111b612647565b602002602001018181525050806002018054611136906123ca565b80601f0160208091040260200160405190810160405280929190818152602001828054611162906123ca565b80156111af5780601f10611184576101008083540402835291602001916111af565b820191906000526020600020905b81548152906001019060200180831161119257829003601f168201915b50505050508383815181106111c6576111c6612647565b60200260200101819052505080806111dd90612405565b915050611084565b509250925092565b6000805b878110156112f957600089898381811061120d5761120d612647565b90506020020160208101906112229190612100565b6040517f29b915b3000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b038a811660248301526044820189905287811660648301528681166084830152919250908216906329b915b39060a40160206040518083038186803b15801561129e57600080fd5b505afa1580156112b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d6919061265d565b156112e6576001925050506112ff565b50806112f181612405565b9150506111f1565b50600090505b979650505050505050565b6000878152602081905260408120546001600160a01b03168061136f5760405162461bcd60e51b815260206004820152601760248201527f54656d706c61746520646f6573206e6f74206578697374000000000000000000604482015260640161061a565b6001600160a01b0386163014156113c85760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038816600090815260036020908152604080832033845290915290205460ff1661143b5760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d60405160200161148a9b9a9998979695949392919061267a565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606086811b8216938501939093528b831b811660348501528a831b1660488401526001600160e01b03198916605c84015294500160408051601f198184030181529181528151602092830120600086815260058452828120919091553381526004909252812080549161152383612405565b919050555082826001600160a01b03167feb39930cdcbb560e6422558a2468b93a215af60063622e63cbb165eba14c32038346338f8f8f8f8f8f8f6040516115749a999897969594939291906125bf565b60405180910390a35050979650505050505050565b6001600160a01b0382166000908152600460205260409020546115c3576001600160a01b0382166000908152600460205260409020600190555b3360008181526003602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917fc2e532a12bbcce2bfa2ef9e4bee80180e4e1b1f78618f0d20bc49a648b577c56910160405180910390a35050565b6060878614801561163f57508784145b801561164a57508782145b6116965760405162461bcd60e51b815260206004820152601960248201527f556e657175616c20706172616d65746572206c656e6774687300000000000000604482015260640161061a565b8767ffffffffffffffff8111156116af576116af612631565b6040519080825280602002602001820160405280156116d8578160200160208202803683370190505b50905060005b888110156117a05761176c8d8d8d8d8d868181106116fe576116fe612647565b905060200201358c8c8781811061171757611717612647565b905060200201358b8b8881811061173057611730612647565b90506020020160208101906117459190612100565b8a8a8981811061175757611757612647565b90506020020160208101906102b79190612100565b82828151811061177e5761177e612647565b911515602092830291909101909101528061179881612405565b9150506116de565b509b9a5050505050505050505050565b60008060006117bf85856117d4565b915091506117cc81611844565b509392505050565b60008082516041141561180b5760208301516040840151606085015160001a6117ff87828585611a02565b9450945050505061183d565b825160401415611835576020830151604084015161182a868383611aef565b93509350505061183d565b506000905060025b9250929050565b600081600481111561185857611858612701565b14156118615750565b600181600481111561187557611875612701565b14156118c35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161061a565b60028160048111156118d7576118d7612701565b14156119255760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161061a565b600381600481111561193957611939612701565b14156119925760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161061a565b60048160048111156119a6576119a6612701565b14156119ff5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161061a565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611a395750600090506003611ae6565b8460ff16601b14158015611a5157508460ff16601c14155b15611a625750600090506004611ae6565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611ab6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611adf57600060019250925050611ae6565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b01611b2987828885611a02565b935093505050935093915050565b828054611b43906123ca565b90600052602060002090601f016020900481019282611b655760008555611bab565b82601f10611b7e57805160ff1916838001178555611bab565b82800160010185558215611bab579182015b82811115611bab578251825591602001919060010190611b90565b50611bb7929150611bbb565b5090565b5b80821115611bb75760008155600101611bbc565b600060208284031215611be257600080fd5b5035919050565b60005b83811015611c04578181015183820152602001611bec565b83811115610c0f5750506000910152565b60008151808452611c2d816020860160208601611be9565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201526000611c696060830184611c15565b95945050505050565b80356001600160a01b0381168114611c8957600080fd5b919050565b60008060408385031215611ca157600080fd5b611caa83611c72565b9150611cb860208401611c72565b90509250929050565b80356001600160e01b031981168114611c8957600080fd5b60008083601f840112611ceb57600080fd5b50813567ffffffffffffffff811115611d0357600080fd5b60208301915083602082850101111561183d57600080fd5b60008060008060008060008060c0898b031215611d3757600080fd5b88359750611d4760208a01611c72565b9650611d5560408a01611c72565b9550611d6360608a01611cc1565b9450608089013567ffffffffffffffff80821115611d8057600080fd5b611d8c8c838d01611cd9565b909650945060a08b0135915080821115611da557600080fd5b50611db28b828c01611cd9565b999c989b5096995094979396929594505050565b8215158152604060208201526000611de16040830184611c15565b949350505050565b60008060008060608587031215611dff57600080fd5b611e0885611c72565b935060208501359250604085013567ffffffffffffffff811115611e2b57600080fd5b611e3787828801611cd9565b95989497509550505050565b600080600060608486031215611e5857600080fd5b83359250611e6860208501611c72565b9150611e7660408501611c72565b90509250925092565b60008060008060008060a08789031215611e9857600080fd5b86359550611ea860208801611c72565b9450611eb660408801611c72565b9350611ec460608801611cc1565b9250608087013567ffffffffffffffff811115611ee057600080fd5b611eec89828a01611cd9565b979a9699509497509295939492505050565b60008060008060008060008060e0898b031215611f1a57600080fd5b611f2389611c72565b975060208901359650611f3860408a01611c72565b9550611f4660608a01611c72565b9450611f5460808a01611c72565b9350611f6260a08a01611cc1565b925060c089013567ffffffffffffffff811115611f7e57600080fd5b611db28b828c01611cd9565b60008083601f840112611f9c57600080fd5b50813567ffffffffffffffff811115611fb457600080fd5b6020830191508360208260051b850101111561183d57600080fd5b60008060208385031215611fe257600080fd5b823567ffffffffffffffff811115611ff957600080fd5b61200585828601611f8a565b90969095509350505050565b600082825180855260208086019550808260051b84010181860160005b8481101561205c57601f1986840301895261204a838351611c15565b9884019892509083019060010161202e565b5090979650505050505050565b606080825284519082018190526000906020906080840190828801845b828110156120ab5781516001600160a01b031684529284019290840190600101612086565b5050508381038285015285518082528683019183019060005b818110156120e0578351835292840192918401916001016120c4565b505084810360408601526120f48187612011565b98975050505050505050565b60006020828403121561211257600080fd5b61211b82611c72565b9392505050565b600080600080600080600060c0888a03121561213d57600080fd5b873567ffffffffffffffff81111561215457600080fd5b6121608a828b01611f8a565b9098509650612173905060208901611c72565b9450604088013593506060880135925061218f60808901611c72565b915061219d60a08901611c72565b905092959891949750929550565b600080600080600080600060c0888a0312156121c657600080fd5b873596506121d660208901611c72565b95506121e460408901611c72565b94506121f260608901611c72565b935061220060808901611cc1565b925060a088013567ffffffffffffffff81111561221c57600080fd5b6122288a828b01611cd9565b989b979a50959850939692959293505050565b80151581146119ff57600080fd5b6000806040838503121561225c57600080fd5b61226583611c72565b915060208301356122758161223b565b809150509250929050565b600080600080600080600080600080600060c08c8e0312156122a157600080fd5b67ffffffffffffffff808d3511156122b857600080fd5b6122c58e8e358f01611f8a565b909c509a506122d660208e01611c72565b99508060408e013511156122e957600080fd5b6122f98e60408f01358f01611f8a565b909950975060608d013581101561230f57600080fd5b61231f8e60608f01358f01611f8a565b909750955060808d013581101561233557600080fd5b6123458e60808f01358f01611f8a565b909550935060a08d013581101561235b57600080fd5b5061236c8d60a08e01358e01611f8a565b81935080925050509295989b509295989b9093969950565b6020808252825182820181905260009190848201906040850190845b818110156123be5783511515835292840192918401916001016123a0565b50909695505050505050565b600181811c908216806123de57607f821691505b602082108114156123ff57634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561242757634e487b7160e01b600052601160045260246000fd5b5060010190565b81818437506000910190815290565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000611c69604083018486612457565b600082516124ac818460208701611be9565b9190910192915050565b602081526000611de1602083018486612457565b6bffffffffffffffffffffffff198560601b16815283601482015281836034830137600091016034019081529392505050565b6001600160a01b0385168152836020820152606060408201526000612526606083018486612457565b9695505050505050565b8c815260006bffffffffffffffffffffffff196060818f821b166020850152818e821b1660348501528c6048850152818c821b1660688501528a607c850152818a821b16609c8501528189821b1660b08501528188821b1660c485015250506001600160e01b0319851660d88301526125ad60dc8301848661242e565b9e9d5050505050505050505050505050565b60006101208c83528b60208401526001600160a01b03808c1660408501528a6060850152808a16608085015280891660a085015280881660c0850152506001600160e01b0319861660e0840152806101008401526126208184018587612457565b9d9c50505050505050505050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561266f57600080fd5b815161211b8161223b565b8b815260006bffffffffffffffffffffffff19808d60601b166020840152808c60601b1660348401528a6048840152896068840152808960601b166088840152808860601b16609c840152808760601b1660b0840152506001600160e01b0319851660c4830152828460c8840137506000910160c8019081529a9950505050505050505050565b634e487b7160e01b600052602160045260246000fdfea26469706673582212208125c69072f5b73d89af7cc14fb8da75fc37036277de16e38207c96e9f01298764736f6c63430008090033", + "deployedBytecode": "0x6080604052600436106100f35760003560e01c806376428c9b1161008a578063acbe180011610059578063acbe1800146102f7578063addf027c14610317578063ca31d58614610337578063f8fa73a11461036457600080fd5b806376428c9b146102405780637e7166f31461026f5780638a33be011461029c578063a81e9f79146102bc57600080fd5b80633c7fe5e3116100c65780633c7fe5e3146101ae57806350743bb9146101c157806352e41f99146102005780636e6be03f1461022057600080fd5b80630a631576146100f85780631d414cbd146101305780631decbf181461015257806332393f2b14610180575b600080fd5b34801561010457600080fd5b50610118610113366004611bd0565b610391565b60405161012793929190611c41565b60405180910390f35b34801561013c57600080fd5b5061015061014b366004611c8e565b610446565b005b34801561015e57600080fd5b5061017261016d366004611d1b565b610566565b604051610127929190611dc6565b34801561018c57600080fd5b506101a061019b366004611de9565b6108d8565b604051908152602001610127565b6101506101bc366004611e43565b610a68565b3480156101cd57600080fd5b506101f06101dc366004611bd0565b600090815260056020526040902054151590565b6040519015158152602001610127565b34801561020c57600080fd5b5061015061021b366004611e7f565b610c15565b34801561022c57600080fd5b506101a061023b366004611efe565b610d30565b34801561024c57600080fd5b5061026061025b366004611fcf565b610fa4565b60405161012793929190612069565b34801561027b57600080fd5b506101a061028a366004612100565b60046020526000908152604090205481565b3480156102a857600080fd5b506101f06102b7366004612122565b6111ed565b3480156102c857600080fd5b506101f06102d7366004611c8e565b600360209081526000928352604080842090915290825290205460ff1681565b34801561030357600080fd5b506101a06103123660046121ab565b61130a565b34801561032357600080fd5b50610150610332366004612249565b611589565b34801561034357600080fd5b50610357610352366004612280565b61162f565b6040516101279190612384565b34801561037057600080fd5b506101a061037f366004612100565b60016020526000908152604090205481565b6000602081905290815260409020805460018201546002830180546001600160a01b039093169391926103c3906123ca565b80601f01602080910402602001604051908101604052809291908181526020018280546103ef906123ca565b801561043c5780601f106104115761010080835404028352916020019161043c565b820191906000526020600020905b81548152906001019060200180831161041f57829003601f168201915b5050505050905083565b336000818152600160205260408120805491924692309290859061046990612405565b91829055506040805160208101959095526bffffffffffffffffffffffff19606094851b8116918601919091529190921b166054830152606882015260880160408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606087811b82169385019390935233831b811660348501529185901b90911660488301529150605c0160408051808303601f19018152828252805160209182012060008581526002835292909220919091556001600160a01b03848116835283923392918716917fd48d52c7c6d0c940f3f8d07591e1800ef3a70daf79929a97ccd80b4494769fc7910160405180910390a4505050565b60008881526005602090815260408083205490516bffffffffffffffffffffffff1960608c811b82169483019490945233841b811660348301528a841b1660488201526001600160e01b03198916605c820152820160405160208183030381529060405280519060200120146106235760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e74000000000060448201526064015b60405180910390fd5b886001600160a01b03166106e585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516106df925061067f91508f908c908c9060200161243d565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b906117b0565b6001600160a01b03161461073b5760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e6174757265000000000000000000000000000000604482015260640161061a565b60008a81526005602052604080822091909155516001600160a01b03891690889061076e908d908a908a90602401612480565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516107c1919061249a565b6000604051808303816000865af19150503d80600081146107fe576040519150601f19603f3d011682016040523d82523d6000602084013e610803565b606091505b50909250905081156108585789896001600160a01b03167fc0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a888860405161084b9291906124b6565b60405180910390a36108cb565b89896001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc6040516108c2906020808252601f908201527f46756c66696c6c6d656e74206661696c656420756e65787065637465646c7900604082015260600190565b60405180910390a35b9850989650505050505050565b60006001600160a01b0385166109305760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b8484848460405160200161094794939291906124ca565b6040516020818303038152906040528051906020012090506040518060600160405280866001600160a01b0316815260200185815260200184848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509390945250508381526020818152604091829020845181547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178155848201516001820155918401518051929350610a1e9260028501929190910190611b37565b50905050807fba204bad31c4ec4b9b54164af94ae10c4e7312f22c0f9c065d6319c928ec9e7a86868686604051610a5894939291906124fd565b60405180910390a2949350505050565b6040516bffffffffffffffffffffffff19606084811b8216602084015283811b8216603484015233901b166048820152605c0160408051601f1981840301815291815281516020928301206000868152600290935291205414610b0d5760405162461bcd60e51b815260206004820152601e60248201527f496e76616c6964207769746864726177616c2066756c66696c6c6d656e740000604482015260640161061a565b6000838152600260209081526040808320929092558151338152349181019190915284916001600160a01b0380851692908616917fadb4840bbd5f924665ae7e0e0c83de5c0fb40a98c9b57dba53a6c978127a622e910160405180910390a46000816001600160a01b03163460405160006040518083038185875af1925050503d8060008114610bb9576040519150601f19603f3d011682016040523d82523d6000602084013e610bbe565b606091505b5050905080610c0f5760405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c65640000000000000000000000000000000000604482015260640161061a565b50505050565b6000868152600560209081526040918290205491516bffffffffffffffffffffffff19606089811b82169383019390935233831b8116603483015287831b1660488201526001600160e01b03198616605c820152016040516020818303038152906040528051906020012014610ccd5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e740000000000604482015260640161061a565b600560008781526020019081526020016000206000905585856001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc8484604051610d209291906124b6565b60405180910390a3505050505050565b60006001600160a01b038916610d885760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b6001600160a01b038516301415610de15760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038716600090815260036020908152604080832033845290915290205460ff16610e545760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d8d604051602001610ea59c9b9a99989796959493929190612530565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff1960608e811b8216938501939093528a831b8116603485015289831b1660488401526001600160e01b03198816605c84015293500160408051601f1981840301815291815281516020928301206000858152600584528281209190915533815260049092528120805491610f3e83612405565b9190505550818a6001600160a01b03167f3a52c462346de2e9436a3868970892956828a11b9c43da1ed43740b12e1125ae8346338e8e8e8e8e8e8e604051610f8f9a999897969594939291906125bf565b60405180910390a35098975050505050505050565b606080808367ffffffffffffffff811115610fc157610fc1612631565b604051908082528060200260200182016040528015610fea578160200160208202803683370190505b5092508367ffffffffffffffff81111561100657611006612631565b60405190808252806020026020018201604052801561102f578160200160208202803683370190505b5091508367ffffffffffffffff81111561104b5761104b612631565b60405190808252806020026020018201604052801561107e57816020015b60608152602001906001900390816110695790505b50905060005b848110156111e55760008060008888858181106110a3576110a3612647565b90506020020135815260200190815260200160002090508060000160009054906101000a90046001600160a01b03168583815181106110e4576110e4612647565b60200260200101906001600160a01b031690816001600160a01b031681525050806001015484838151811061111b5761111b612647565b602002602001018181525050806002018054611136906123ca565b80601f0160208091040260200160405190810160405280929190818152602001828054611162906123ca565b80156111af5780601f10611184576101008083540402835291602001916111af565b820191906000526020600020905b81548152906001019060200180831161119257829003601f168201915b50505050508383815181106111c6576111c6612647565b60200260200101819052505080806111dd90612405565b915050611084565b509250925092565b6000805b878110156112f957600089898381811061120d5761120d612647565b90506020020160208101906112229190612100565b6040517f29b915b3000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b038a811660248301526044820189905287811660648301528681166084830152919250908216906329b915b39060a40160206040518083038186803b15801561129e57600080fd5b505afa1580156112b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d6919061265d565b156112e6576001925050506112ff565b50806112f181612405565b9150506111f1565b50600090505b979650505050505050565b6000878152602081905260408120546001600160a01b03168061136f5760405162461bcd60e51b815260206004820152601760248201527f54656d706c61746520646f6573206e6f74206578697374000000000000000000604482015260640161061a565b6001600160a01b0386163014156113c85760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038816600090815260036020908152604080832033845290915290205460ff1661143b5760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d60405160200161148a9b9a9998979695949392919061267a565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606086811b8216938501939093528b831b811660348501528a831b1660488401526001600160e01b03198916605c84015294500160408051601f198184030181529181528151602092830120600086815260058452828120919091553381526004909252812080549161152383612405565b919050555082826001600160a01b03167feb39930cdcbb560e6422558a2468b93a215af60063622e63cbb165eba14c32038346338f8f8f8f8f8f8f6040516115749a999897969594939291906125bf565b60405180910390a35050979650505050505050565b6001600160a01b0382166000908152600460205260409020546115c3576001600160a01b0382166000908152600460205260409020600190555b3360008181526003602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917fc2e532a12bbcce2bfa2ef9e4bee80180e4e1b1f78618f0d20bc49a648b577c56910160405180910390a35050565b6060878614801561163f57508784145b801561164a57508782145b6116965760405162461bcd60e51b815260206004820152601960248201527f556e657175616c20706172616d65746572206c656e6774687300000000000000604482015260640161061a565b8767ffffffffffffffff8111156116af576116af612631565b6040519080825280602002602001820160405280156116d8578160200160208202803683370190505b50905060005b888110156117a05761176c8d8d8d8d8d868181106116fe576116fe612647565b905060200201358c8c8781811061171757611717612647565b905060200201358b8b8881811061173057611730612647565b90506020020160208101906117459190612100565b8a8a8981811061175757611757612647565b90506020020160208101906102b79190612100565b82828151811061177e5761177e612647565b911515602092830291909101909101528061179881612405565b9150506116de565b509b9a5050505050505050505050565b60008060006117bf85856117d4565b915091506117cc81611844565b509392505050565b60008082516041141561180b5760208301516040840151606085015160001a6117ff87828585611a02565b9450945050505061183d565b825160401415611835576020830151604084015161182a868383611aef565b93509350505061183d565b506000905060025b9250929050565b600081600481111561185857611858612701565b14156118615750565b600181600481111561187557611875612701565b14156118c35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161061a565b60028160048111156118d7576118d7612701565b14156119255760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161061a565b600381600481111561193957611939612701565b14156119925760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161061a565b60048160048111156119a6576119a6612701565b14156119ff5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161061a565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611a395750600090506003611ae6565b8460ff16601b14158015611a5157508460ff16601c14155b15611a625750600090506004611ae6565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611ab6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611adf57600060019250925050611ae6565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b01611b2987828885611a02565b935093505050935093915050565b828054611b43906123ca565b90600052602060002090601f016020900481019282611b655760008555611bab565b82601f10611b7e57805160ff1916838001178555611bab565b82800160010185558215611bab579182015b82811115611bab578251825591602001919060010190611b90565b50611bb7929150611bbb565b5090565b5b80821115611bb75760008155600101611bbc565b600060208284031215611be257600080fd5b5035919050565b60005b83811015611c04578181015183820152602001611bec565b83811115610c0f5750506000910152565b60008151808452611c2d816020860160208601611be9565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201526000611c696060830184611c15565b95945050505050565b80356001600160a01b0381168114611c8957600080fd5b919050565b60008060408385031215611ca157600080fd5b611caa83611c72565b9150611cb860208401611c72565b90509250929050565b80356001600160e01b031981168114611c8957600080fd5b60008083601f840112611ceb57600080fd5b50813567ffffffffffffffff811115611d0357600080fd5b60208301915083602082850101111561183d57600080fd5b60008060008060008060008060c0898b031215611d3757600080fd5b88359750611d4760208a01611c72565b9650611d5560408a01611c72565b9550611d6360608a01611cc1565b9450608089013567ffffffffffffffff80821115611d8057600080fd5b611d8c8c838d01611cd9565b909650945060a08b0135915080821115611da557600080fd5b50611db28b828c01611cd9565b999c989b5096995094979396929594505050565b8215158152604060208201526000611de16040830184611c15565b949350505050565b60008060008060608587031215611dff57600080fd5b611e0885611c72565b935060208501359250604085013567ffffffffffffffff811115611e2b57600080fd5b611e3787828801611cd9565b95989497509550505050565b600080600060608486031215611e5857600080fd5b83359250611e6860208501611c72565b9150611e7660408501611c72565b90509250925092565b60008060008060008060a08789031215611e9857600080fd5b86359550611ea860208801611c72565b9450611eb660408801611c72565b9350611ec460608801611cc1565b9250608087013567ffffffffffffffff811115611ee057600080fd5b611eec89828a01611cd9565b979a9699509497509295939492505050565b60008060008060008060008060e0898b031215611f1a57600080fd5b611f2389611c72565b975060208901359650611f3860408a01611c72565b9550611f4660608a01611c72565b9450611f5460808a01611c72565b9350611f6260a08a01611cc1565b925060c089013567ffffffffffffffff811115611f7e57600080fd5b611db28b828c01611cd9565b60008083601f840112611f9c57600080fd5b50813567ffffffffffffffff811115611fb457600080fd5b6020830191508360208260051b850101111561183d57600080fd5b60008060208385031215611fe257600080fd5b823567ffffffffffffffff811115611ff957600080fd5b61200585828601611f8a565b90969095509350505050565b600082825180855260208086019550808260051b84010181860160005b8481101561205c57601f1986840301895261204a838351611c15565b9884019892509083019060010161202e565b5090979650505050505050565b606080825284519082018190526000906020906080840190828801845b828110156120ab5781516001600160a01b031684529284019290840190600101612086565b5050508381038285015285518082528683019183019060005b818110156120e0578351835292840192918401916001016120c4565b505084810360408601526120f48187612011565b98975050505050505050565b60006020828403121561211257600080fd5b61211b82611c72565b9392505050565b600080600080600080600060c0888a03121561213d57600080fd5b873567ffffffffffffffff81111561215457600080fd5b6121608a828b01611f8a565b9098509650612173905060208901611c72565b9450604088013593506060880135925061218f60808901611c72565b915061219d60a08901611c72565b905092959891949750929550565b600080600080600080600060c0888a0312156121c657600080fd5b873596506121d660208901611c72565b95506121e460408901611c72565b94506121f260608901611c72565b935061220060808901611cc1565b925060a088013567ffffffffffffffff81111561221c57600080fd5b6122288a828b01611cd9565b989b979a50959850939692959293505050565b80151581146119ff57600080fd5b6000806040838503121561225c57600080fd5b61226583611c72565b915060208301356122758161223b565b809150509250929050565b600080600080600080600080600080600060c08c8e0312156122a157600080fd5b67ffffffffffffffff808d3511156122b857600080fd5b6122c58e8e358f01611f8a565b909c509a506122d660208e01611c72565b99508060408e013511156122e957600080fd5b6122f98e60408f01358f01611f8a565b909950975060608d013581101561230f57600080fd5b61231f8e60608f01358f01611f8a565b909750955060808d013581101561233557600080fd5b6123458e60808f01358f01611f8a565b909550935060a08d013581101561235b57600080fd5b5061236c8d60a08e01358e01611f8a565b81935080925050509295989b509295989b9093969950565b6020808252825182820181905260009190848201906040850190845b818110156123be5783511515835292840192918401916001016123a0565b50909695505050505050565b600181811c908216806123de57607f821691505b602082108114156123ff57634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561242757634e487b7160e01b600052601160045260246000fd5b5060010190565b81818437506000910190815290565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000611c69604083018486612457565b600082516124ac818460208701611be9565b9190910192915050565b602081526000611de1602083018486612457565b6bffffffffffffffffffffffff198560601b16815283601482015281836034830137600091016034019081529392505050565b6001600160a01b0385168152836020820152606060408201526000612526606083018486612457565b9695505050505050565b8c815260006bffffffffffffffffffffffff196060818f821b166020850152818e821b1660348501528c6048850152818c821b1660688501528a607c850152818a821b16609c8501528189821b1660b08501528188821b1660c485015250506001600160e01b0319851660d88301526125ad60dc8301848661242e565b9e9d5050505050505050505050505050565b60006101208c83528b60208401526001600160a01b03808c1660408501528a6060850152808a16608085015280891660a085015280881660c0850152506001600160e01b0319861660e0840152806101008401526126208184018587612457565b9d9c50505050505050505050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561266f57600080fd5b815161211b8161223b565b8b815260006bffffffffffffffffffffffff19808d60601b166020840152808c60601b1660348401528a6048840152896068840152808960601b166088840152808860601b16609c840152808760601b1660b0840152506001600160e01b0319851660c4830152828460c8840137506000910160c8019081529a9950505050505050505050565b634e487b7160e01b600052602160045260246000fdfea26469706673582212208125c69072f5b73d89af7cc14fb8da75fc37036277de16e38207c96e9f01298764736f6c63430008090033", + "devdoc": { + "kind": "dev", + "methods": { + "checkAuthorizationStatus(address[],address,bytes32,bytes32,address,address)": { + "details": "This method is meant to be called off-chain, statically by the Airnode to decide if it should respond to a request. The requester can also call it, yet this function returning true should not be taken as a guarantee of the subsequent request being fulfilled. It is enough for only one of the authorizer contracts to return true for the request to be authorized.", + "params": { + "airnode": "Airnode address", + "authorizers": "Authorizer contract addresses", + "endpointId": "Endpoint ID", + "requestId": "Request ID", + "requester": "Requester address", + "sponsor": "Sponsor address" + }, + "returns": { + "status": "Authorization status of the request" + } + }, + "checkAuthorizationStatuses(address[],address,bytes32[],bytes32[],address[],address[])": { + "params": { + "airnode": "Airnode address", + "authorizers": "Authorizer contract addresses", + "endpointIds": "Endpoint IDs", + "requestIds": "Request IDs", + "requesters": "Requester addresses", + "sponsors": "Sponsor addresses" + }, + "returns": { + "statuses": "Authorization statuses of the request" + } + }, + "createTemplate(address,bytes32,bytes)": { + "details": "A specific set of request parameters will always have the same template ID. This means a few things: (1) You can compute the expected ID of a template before creating it, (2) Creating a new template with the same parameters will overwrite the old one and return the same ID, (3) After you query a template with its ID, you can verify its integrity by applying the hash and comparing the result with the ID.", + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID (allowed to be `bytes32(0)`)", + "parameters": "Static request parameters (i.e., parameters that will not change between requests, unlike the dynamic parameters determined at request-time)" + }, + "returns": { + "templateId": "Request template ID" + } + }, + "fail(bytes32,address,address,bytes4,string)": { + "details": "Airnode should fall back to this if a request cannot be fulfilled because static call to `fulfill()` returns `false` for `callSuccess`", + "params": { + "airnode": "Airnode address", + "errorMessage": "A message that explains why the request has failed", + "fulfillAddress": "Address that will be called to fulfill", + "fulfillFunctionId": "Signature of the function that will be called to fulfill", + "requestId": "Request ID" + } + }, + "fulfill(bytes32,address,address,bytes4,bytes,bytes)": { + "details": "The data is ABI-encoded as a `bytes` type, with its format depending on the request specifications. This will not revert depending on the external call. However, it will return `false` if the external call reverts or if there is no function with a matching signature at `fulfillAddress`. On the other hand, it will return `true` if the external call returns successfully or if there is no contract deployed at `fulfillAddress`. If `callSuccess` is `false`, `callData` can be decoded to retrieve the revert string. This function emits its event after an untrusted low-level call, meaning that the order of these events within the transaction should not be taken seriously, yet the content will be sound.", + "params": { + "airnode": "Airnode address", + "data": "Fulfillment data", + "fulfillAddress": "Address that will be called to fulfill", + "fulfillFunctionId": "Signature of the function that will be called to fulfill", + "requestId": "Request ID" + }, + "returns": { + "callData": "Data returned by the fulfillment call (if there is any)", + "callSuccess": "If the fulfillment call succeeded" + } + }, + "fulfillWithdrawal(bytes32,address,address)": { + "details": "The Airnode sends the funds to the sponsor through this method to emit an event that indicates that the withdrawal request has been fulfilled", + "params": { + "airnode": "Airnode address", + "sponsor": "Sponsor address", + "withdrawalRequestId": "Withdrawal request ID" + } + }, + "getTemplates(bytes32[])": { + "details": "Does not revert if the templates being indexed do not exist", + "params": { + "templateIds": "Request template IDs" + }, + "returns": { + "airnodes": "Array of Airnode addresses", + "endpointIds": "Array of endpoint IDs", + "parameters": "Array of request parameters" + } + }, + "makeFullRequest(address,bytes32,address,address,address,bytes4,bytes)": { + "details": "`fulfillAddress` is not allowed to be the address of this contract. This is not actually needed to protect users that use the protocol as intended, but it is done for good measure.", + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID (allowed to be `bytes32(0)`)", + "fulfillAddress": "Address that will be called to fulfill", + "fulfillFunctionId": "Signature of the function that will be called to fulfill", + "parameters": "All request parameters", + "sponsor": "Sponsor address", + "sponsorWallet": "Sponsor wallet that is requested to fulfill the request" + }, + "returns": { + "requestId": "Request ID" + } + }, + "makeTemplateRequest(bytes32,address,address,address,bytes4,bytes)": { + "details": "`fulfillAddress` is not allowed to be the address of this contract. This is not actually needed to protect users that use the protocol as intended, but it is done for good measure.", + "params": { + "fulfillAddress": "Address that will be called to fulfill", + "fulfillFunctionId": "Signature of the function that will be called to fulfill", + "parameters": "Parameters provided by the requester in addition to the parameters in the template", + "sponsor": "Sponsor address", + "sponsorWallet": "Sponsor wallet that is requested to fulfill the request", + "templateId": "Template ID" + }, + "returns": { + "requestId": "Request ID" + } + }, + "requestIsAwaitingFulfillment(bytes32)": { + "details": "If a requester has made a request, received a request ID but did not hear back, it can call this method to check if the Airnode has called back `fail()` instead.", + "params": { + "requestId": "Request ID" + }, + "returns": { + "isAwaitingFulfillment": "If the request is awaiting fulfillment (i.e., `true` if `fulfill()` or `fail()` is not called back yet, `false` otherwise)" + } + }, + "requestWithdrawal(address,address)": { + "details": "We do not need to use the withdrawal request parameters in the request ID hash to validate them at the node-side because all of the parameters are used during fulfillment and will get validated on-chain. The first withdrawal request a sponsor will make will cost slightly higher gas than the rest due to how the request counter is implemented.", + "params": { + "airnode": "Airnode address", + "sponsorWallet": "Sponsor wallet that the withdrawal is requested from" + } + }, + "setSponsorshipStatus(address,bool)": { + "details": "This is not Airnode-specific, i.e., the sponsor allows the requester's requests to be fulfilled through its sponsor wallets across all Airnodes", + "params": { + "requester": "Requester address", + "sponsorshipStatus": "Sponsorship status" + } + } + }, + "stateVariables": { + "requestIdToFulfillmentParameters": { + "details": "Hash of expected fulfillment parameters are kept to verify that the fulfillment will be done with the correct parameters. This value is also used to check if the fulfillment for the particular request is expected, i.e., if there are recorded fulfillment parameters." + }, + "requesterToRequestCountPlusOne": { + "details": "Can be used to calculate the ID of the next request the requester will make" + } + }, + "title": "Contract that implements the Airnode request–response protocol (RRP)", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "checkAuthorizationStatus(address[],address,bytes32,bytes32,address,address)": { + "notice": "Uses the authorizer contracts of an Airnode to decide if a request is authorized. Once an Airnode receives a request, it calls this method to determine if it should respond. Similarly, third parties can use this method to determine if a particular request would be authorized." + }, + "checkAuthorizationStatuses(address[],address,bytes32[],bytes32[],address[],address[])": { + "notice": "A convenience function to make multiple authorization status checks with a single call" + }, + "createTemplate(address,bytes32,bytes)": { + "notice": "Creates a request template with the given parameters, addressable by the ID it returns" + }, + "fail(bytes32,address,address,bytes4,string)": { + "notice": "Called by Airnode if the request cannot be fulfilled" + }, + "fulfill(bytes32,address,address,bytes4,bytes,bytes)": { + "notice": "Called by Airnode to fulfill the request (template or full)" + }, + "fulfillWithdrawal(bytes32,address,address)": { + "notice": "Called by the Airnode using the sponsor wallet to fulfill the withdrawal request made by the sponsor" + }, + "getTemplates(bytes32[])": { + "notice": "A convenience method to retrieve multiple templates with a single call" + }, + "makeFullRequest(address,bytes32,address,address,address,bytes4,bytes)": { + "notice": "Called by the requester to make a full request, which provides all of its parameters as arguments and does not refer to a template" + }, + "makeTemplateRequest(bytes32,address,address,address,bytes4,bytes)": { + "notice": "Called by the requester to make a request that refers to a template for the Airnode address, endpoint ID and parameters" + }, + "requestIsAwaitingFulfillment(bytes32)": { + "notice": "Called to check if the request with the ID is made but not fulfilled/failed yet" + }, + "requestWithdrawal(address,address)": { + "notice": "Called by a sponsor to create a request for the Airnode to send the funds kept in the respective sponsor wallet to the sponsor" + }, + "requesterToRequestCountPlusOne(address)": { + "notice": "Called to get the request count of the requester plus one" + }, + "setSponsorshipStatus(address,bool)": { + "notice": "Called by the sponsor to set the sponsorship status of a requester, i.e., allow or disallow a requester to make requests that will be fulfilled by the sponsor wallet" + }, + "sponsorToRequesterToSponsorshipStatus(address,address)": { + "notice": "Called to get the sponsorship status for a sponsor–requester pair" + }, + "sponsorToWithdrawalRequestCount(address)": { + "notice": "Called to get the withdrawal request count of the sponsor" + }, + "templates(bytes32)": { + "notice": "Called to get a template" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 3643, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "templates", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_struct(Template)3636_storage)" + }, + { + "astId": 3796, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "sponsorToWithdrawalRequestCount", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 3801, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "withdrawalRequestIdToParameters", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_bytes32,t_bytes32)" + }, + { + "astId": 2913, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "sponsorToRequesterToSponsorshipStatus", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_mapping(t_address,t_bool))" + }, + { + "astId": 2919, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "requesterToRequestCountPlusOne", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 2924, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "requestIdToFulfillmentParameters", + "offset": 0, + "slot": "5", + "type": "t_mapping(t_bytes32,t_bytes32)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_bytes_storage": { + "encoding": "bytes", + "label": "bytes", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_mapping(t_address,t_bool))": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => mapping(address => bool))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_bool)" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_mapping(t_bytes32,t_bytes32)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => bytes32)", + "numberOfBytes": "32", + "value": "t_bytes32" + }, + "t_mapping(t_bytes32,t_struct(Template)3636_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct TemplateUtilsV0.Template)", + "numberOfBytes": "32", + "value": "t_struct(Template)3636_storage" + }, + "t_struct(Template)3636_storage": { + "encoding": "inplace", + "label": "struct TemplateUtilsV0.Template", + "members": [ + { + "astId": 3631, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "airnode", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 3633, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "endpointId", + "offset": 0, + "slot": "1", + "type": "t_bytes32" + }, + { + "astId": 3635, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "parameters", + "offset": 0, + "slot": "2", + "type": "t_bytes_storage" + } + ], + "numberOfBytes": "96" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/packages/airnode-protocol/deployments/lightlink-goerli-testnet/AirnodeRrpV0DryRun.json b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/AirnodeRrpV0DryRun.json new file mode 100644 index 0000000000..6425f6ad4a --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/AirnodeRrpV0DryRun.json @@ -0,0 +1,163 @@ +{ + "address": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "FulfilledRequest", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "fulfill", + "outputs": [ + { + "internalType": "bool", + "name": "callSuccess", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0xc0da53690bb527de6dfc1fe11f334485c2860319d85ba16ddd8bbbac02a186d7", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xc97965EbD0f2123Cc31BEc63E18A8Ce9Ef6a1e7e", + "contractAddress": "0x0000000000000000000000000000000000000000", + "transactionIndex": 0, + "gasUsed": "583060", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x1665276b6140fb0b08623d84d0c296f16bc9a6c7d1dcc954a297d1e56bc1eea9", + "transactionHash": "0xc0da53690bb527de6dfc1fe11f334485c2860319d85ba16ddd8bbbac02a186d7", + "logs": [], + "blockNumber": 56898258, + "cumulativeGasUsed": "583060", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "d8591a026515856ab7bc7dc284bf2fbe", + "metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FulfilledRequest\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"callSuccess\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Typically, contracts are built to revert when an external call they make reverts. In contrast, AirnodeRrpV0 does not revert when the external call during the fulfillment reverts, and instead fails gracefully by emitting a `FailedRequest` event. This event signals to the future invocations of the stateless Airnode to not retry the failed fulfillment. Although this approach meets the intended purpose, it disables Airnode from calling `eth_estimateGas` on `fulfill()` to estimate the gas amount that will be used to execute a fulfillment successfully. Specifically, since `eth_estimateGas` looks for the lowest gas limit that results in the transaction not reverting, and AirnodeRrpV0's `fulfill()` does not revert when its external call reverts (because it runs out of gas), `eth_estimateGas` will not necessarily return a gas amount that will result in the fulfillment to be successful even if such an amount exists. As a solution, Airnode calls `eth_estimateGas` on AirnodeRrpV0DryRun's `fulfill()` and the external call of the fulfillment, and add these up to find the gas limit required to execute a successful fulfillment. This sum is an overestimation of the actual requirement, as it includes an additional base fee (21,000 gas on Ethereum).\",\"kind\":\"dev\",\"methods\":{\"fulfill(bytes32,address,address,bytes4,bytes,bytes)\":{\"details\":\"Refer to AirnodeRrpV0's `fulfill()` for more information\",\"params\":{\"airnode\":\"Airnode address\",\"data\":\"Fulfillment data\",\"fulfillAddress\":\"Address that will be called to fulfill\",\"fulfillFunctionId\":\"Signature of the function that will be called to fulfill\",\"requestId\":\"Request ID\"},\"returns\":{\"callData\":\"Data returned by the fulfillment call (if there is any)\",\"callSuccess\":\"If the fulfillment call succeeded\"}}},\"stateVariables\":{\"requestIdToFulfillmentParameters\":{\"details\":\"This mapping is kept as it is in AirnodeRrpV0 to closely simulate the fulfillment. All of its keys will map to zero values.\"}},\"title\":\"Contract that complements Airnode request\\u2013response protocol (RRP) to allow Airnode to estimate the gas required to execute a fulfillment\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"fulfill(bytes32,address,address,bytes4,bytes,bytes)\":{\"notice\":\"Used by Airnode to estimate the gas amount needed to fulfill the request (excluding the external call). Do not call this function, as it will have no practical effect.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/rrp/AirnodeRrpV0DryRun.sol\":\"AirnodeRrpV0DryRun\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s;\\n uint8 v;\\n assembly {\\n s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\\n v := add(shr(255, vs), 27)\\n }\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xe9e291de7ffe06e66503c6700b1bb84ff6e0989cbb974653628d8994e7c97f03\",\"license\":\"MIT\"},\"contracts/rrp/AirnodeRrpV0DryRun.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\n\\n/// @title Contract that complements Airnode request\\u2013response protocol (RRP) to\\n/// allow Airnode to estimate the gas required to execute a fulfillment\\n/// @dev Typically, contracts are built to revert when an external call they\\n/// make reverts. In contrast, AirnodeRrpV0 does not revert when the external\\n/// call during the fulfillment reverts, and instead fails gracefully by\\n/// emitting a `FailedRequest` event. This event signals to the future\\n/// invocations of the stateless Airnode to not retry the failed fulfillment.\\n/// Although this approach meets the intended purpose, it disables Airnode from\\n/// calling `eth_estimateGas` on `fulfill()` to estimate the gas amount that\\n/// will be used to execute a fulfillment successfully. Specifically, since\\n/// `eth_estimateGas` looks for the lowest gas limit that results in the\\n/// transaction not reverting, and AirnodeRrpV0's `fulfill()` does not revert\\n/// when its external call reverts (because it runs out of gas),\\n/// `eth_estimateGas` will not necessarily return a gas amount that will result\\n/// in the fulfillment to be successful even if such an amount exists.\\n/// As a solution, Airnode calls `eth_estimateGas` on AirnodeRrpV0DryRun's\\n/// `fulfill()` and the external call of the fulfillment, and add these up to\\n/// find the gas limit required to execute a successful fulfillment. This\\n/// sum is an overestimation of the actual requirement, as it includes an\\n/// additional base fee (21,000 gas on Ethereum).\\ncontract AirnodeRrpV0DryRun\\n{\\n using ECDSA for bytes32;\\n\\n event FulfilledRequest(\\n address indexed airnode,\\n bytes32 indexed requestId,\\n bytes data\\n );\\n\\n /// @dev This mapping is kept as it is in AirnodeRrpV0 to closely simulate\\n /// the fulfillment. All of its keys will map to zero values.\\n mapping(bytes32 => bytes32) private requestIdToFulfillmentParameters;\\n\\n /// @notice Used by Airnode to estimate the gas amount needed to fulfill\\n /// the request (excluding the external call). Do not call this function,\\n /// as it will have no practical effect.\\n /// @dev Refer to AirnodeRrpV0's `fulfill()` for more information\\n /// @param requestId Request ID\\n /// @param airnode Airnode address\\n /// @param data Fulfillment data\\n /// @param fulfillAddress Address that will be called to fulfill\\n /// @param fulfillFunctionId Signature of the function that will be called\\n /// to fulfill\\n /// @return callSuccess If the fulfillment call succeeded\\n /// @return callData Data returned by the fulfillment call (if there is\\n /// any)\\n function fulfill(\\n bytes32 requestId,\\n address airnode,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata data,\\n bytes calldata signature\\n ) external returns (bool callSuccess, bytes memory callData) {\\n // The line below is kept the same, except that the condition is\\n // reversed to ensure that it never reverts. All\\n // `requestIdToFulfillmentParameters` values are zero and virtually no\\n // `keccak256()` output will be equal to that.\\n require(\\n keccak256(\\n abi.encodePacked(\\n airnode,\\n msg.sender,\\n fulfillAddress,\\n fulfillFunctionId\\n )\\n ) != requestIdToFulfillmentParameters[requestId],\\n \\\"Dummy revert string\\\"\\n );\\n // The line below does not need to be modified\\n require(\\n (\\n keccak256(abi.encodePacked(requestId, data))\\n .toEthSignedMessageHash()\\n ).recover(signature) == airnode,\\n \\\"Invalid signature\\\"\\n );\\n // We cannot call `fulfillAddress` below because (1) we do not want\\n // this function to actually fulfill the request (2) the fulfill\\n // function will be behind an `onlyAirnodeRrp` modifier and will reject\\n // the calls from AirnodeRrpV0DryRun.\\n // Instead, we call an address that we know to not contain any\\n // bytecode, which will result in the call to not revert or spend extra\\n // gas. Since we have already confirmed that `airnode` has signed a\\n // hash, it is guaranteed to be an EOA and we can use it as a dummy\\n // call target.\\n (callSuccess, callData) = airnode.call( // solhint-disable-line avoid-low-level-calls\\n abi.encodeWithSelector(fulfillFunctionId, requestId, data)\\n );\\n // If the external call above does not succeed, the `eth_estimateGas`\\n // called on the external call will not be able to return a gas amount.\\n // AirnodeRrpV0DryRun's `fulfill()` optimistically estimates the\\n // AirnodeRrpV0 overhead of a fulfillment, and expects Airnode to\\n // detect if the external call will succeed (by calling\\n // `eth_estimateGas` on it) independently. Therefore, we do not need to\\n // consider the unhappy path here.\\n if (callSuccess) {\\n emit FulfilledRequest(airnode, requestId, data);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x5a3243f6e878bc2dbc853033bac3b73ba9aea70b02db49cca9a7e837cf24b170\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50610997806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80631decbf1814610030575b600080fd5b61004361003e366004610756565b61005a565b604051610051929190610858565b60405180910390f35b6000888152602081815260408083205490516bffffffffffffffffffffffff1960608c811b82169483019490945233841b811660348301528a841b1660488201527fffffffff000000000000000000000000000000000000000000000000000000008916605c820152820160405160208183030381529060405280519060200120141561012e5760405162461bcd60e51b815260206004820152601360248201527f44756d6d792072657665727420737472696e670000000000000000000000000060448201526064015b60405180910390fd5b886001600160a01b03166101f085858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516101ea925061018a91508f908c908c90602001610894565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90610371565b6001600160a01b0316146102465760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610125565b886001600160a01b0316878b8888604051602401610266939291906108d7565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516102d191906108fa565b6000604051808303816000865af19150503d806000811461030e576040519150601f19603f3d011682016040523d82523d6000602084013e610313565b606091505b50909250905081156103645789896001600160a01b03167fc0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a888860405161035b929190610916565b60405180910390a35b9850989650505050505050565b60008060006103808585610395565b9150915061038d81610405565b509392505050565b6000808251604114156103cc5760208301516040840151606085015160001a6103c0878285856105c3565b945094505050506103fe565b8251604014156103f657602083015160408401516103eb8683836106b0565b9350935050506103fe565b506000905060025b9250929050565b600081600481111561041957610419610932565b14156104225750565b600181600481111561043657610436610932565b14156104845760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610125565b600281600481111561049857610498610932565b14156104e65760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610125565b60038160048111156104fa576104fa610932565b14156105535760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610125565b600481600481111561056757610567610932565b14156105c05760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610125565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156105fa57506000905060036106a7565b8460ff16601b1415801561061257508460ff16601c14155b1561062357506000905060046106a7565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610677573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166106a0576000600192509250506106a7565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b016106ea878288856105c3565b935093505050935093915050565b80356001600160a01b038116811461070f57600080fd5b919050565b60008083601f84011261072657600080fd5b50813567ffffffffffffffff81111561073e57600080fd5b6020830191508360208285010111156103fe57600080fd5b60008060008060008060008060c0898b03121561077257600080fd5b8835975061078260208a016106f8565b965061079060408a016106f8565b955060608901357fffffffff00000000000000000000000000000000000000000000000000000000811681146107c557600080fd5b9450608089013567ffffffffffffffff808211156107e257600080fd5b6107ee8c838d01610714565b909650945060a08b013591508082111561080757600080fd5b506108148b828c01610714565b999c989b5096995094979396929594505050565b60005b8381101561084357818101518382015260200161082b565b83811115610852576000848401525b50505050565b8215158152604060208201526000825180604084015261087f816060850160208701610828565b601f01601f1916919091016060019392505050565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8381526040602082015260006108f16040830184866108ae565b95945050505050565b6000825161090c818460208701610828565b9190910192915050565b60208152600061092a6020830184866108ae565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212201f6f9d6bb1fa5e17ffc6a138eebeb4fdd93d3c2b7fe4bcc141ddae7c7708cb6464736f6c63430008090033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c80631decbf1814610030575b600080fd5b61004361003e366004610756565b61005a565b604051610051929190610858565b60405180910390f35b6000888152602081815260408083205490516bffffffffffffffffffffffff1960608c811b82169483019490945233841b811660348301528a841b1660488201527fffffffff000000000000000000000000000000000000000000000000000000008916605c820152820160405160208183030381529060405280519060200120141561012e5760405162461bcd60e51b815260206004820152601360248201527f44756d6d792072657665727420737472696e670000000000000000000000000060448201526064015b60405180910390fd5b886001600160a01b03166101f085858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516101ea925061018a91508f908c908c90602001610894565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90610371565b6001600160a01b0316146102465760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610125565b886001600160a01b0316878b8888604051602401610266939291906108d7565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516102d191906108fa565b6000604051808303816000865af19150503d806000811461030e576040519150601f19603f3d011682016040523d82523d6000602084013e610313565b606091505b50909250905081156103645789896001600160a01b03167fc0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a888860405161035b929190610916565b60405180910390a35b9850989650505050505050565b60008060006103808585610395565b9150915061038d81610405565b509392505050565b6000808251604114156103cc5760208301516040840151606085015160001a6103c0878285856105c3565b945094505050506103fe565b8251604014156103f657602083015160408401516103eb8683836106b0565b9350935050506103fe565b506000905060025b9250929050565b600081600481111561041957610419610932565b14156104225750565b600181600481111561043657610436610932565b14156104845760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610125565b600281600481111561049857610498610932565b14156104e65760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610125565b60038160048111156104fa576104fa610932565b14156105535760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610125565b600481600481111561056757610567610932565b14156105c05760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610125565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156105fa57506000905060036106a7565b8460ff16601b1415801561061257508460ff16601c14155b1561062357506000905060046106a7565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610677573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166106a0576000600192509250506106a7565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b016106ea878288856105c3565b935093505050935093915050565b80356001600160a01b038116811461070f57600080fd5b919050565b60008083601f84011261072657600080fd5b50813567ffffffffffffffff81111561073e57600080fd5b6020830191508360208285010111156103fe57600080fd5b60008060008060008060008060c0898b03121561077257600080fd5b8835975061078260208a016106f8565b965061079060408a016106f8565b955060608901357fffffffff00000000000000000000000000000000000000000000000000000000811681146107c557600080fd5b9450608089013567ffffffffffffffff808211156107e257600080fd5b6107ee8c838d01610714565b909650945060a08b013591508082111561080757600080fd5b506108148b828c01610714565b999c989b5096995094979396929594505050565b60005b8381101561084357818101518382015260200161082b565b83811115610852576000848401525b50505050565b8215158152604060208201526000825180604084015261087f816060850160208701610828565b601f01601f1916919091016060019392505050565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8381526040602082015260006108f16040830184866108ae565b95945050505050565b6000825161090c818460208701610828565b9190910192915050565b60208152600061092a6020830184866108ae565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212201f6f9d6bb1fa5e17ffc6a138eebeb4fdd93d3c2b7fe4bcc141ddae7c7708cb6464736f6c63430008090033", + "devdoc": { + "details": "Typically, contracts are built to revert when an external call they make reverts. In contrast, AirnodeRrpV0 does not revert when the external call during the fulfillment reverts, and instead fails gracefully by emitting a `FailedRequest` event. This event signals to the future invocations of the stateless Airnode to not retry the failed fulfillment. Although this approach meets the intended purpose, it disables Airnode from calling `eth_estimateGas` on `fulfill()` to estimate the gas amount that will be used to execute a fulfillment successfully. Specifically, since `eth_estimateGas` looks for the lowest gas limit that results in the transaction not reverting, and AirnodeRrpV0's `fulfill()` does not revert when its external call reverts (because it runs out of gas), `eth_estimateGas` will not necessarily return a gas amount that will result in the fulfillment to be successful even if such an amount exists. As a solution, Airnode calls `eth_estimateGas` on AirnodeRrpV0DryRun's `fulfill()` and the external call of the fulfillment, and add these up to find the gas limit required to execute a successful fulfillment. This sum is an overestimation of the actual requirement, as it includes an additional base fee (21,000 gas on Ethereum).", + "kind": "dev", + "methods": { + "fulfill(bytes32,address,address,bytes4,bytes,bytes)": { + "details": "Refer to AirnodeRrpV0's `fulfill()` for more information", + "params": { + "airnode": "Airnode address", + "data": "Fulfillment data", + "fulfillAddress": "Address that will be called to fulfill", + "fulfillFunctionId": "Signature of the function that will be called to fulfill", + "requestId": "Request ID" + }, + "returns": { + "callData": "Data returned by the fulfillment call (if there is any)", + "callSuccess": "If the fulfillment call succeeded" + } + } + }, + "stateVariables": { + "requestIdToFulfillmentParameters": { + "details": "This mapping is kept as it is in AirnodeRrpV0 to closely simulate the fulfillment. All of its keys will map to zero values." + } + }, + "title": "Contract that complements Airnode request–response protocol (RRP) to allow Airnode to estimate the gas required to execute a fulfillment", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "fulfill(bytes32,address,address,bytes4,bytes,bytes)": { + "notice": "Used by Airnode to estimate the gas amount needed to fulfill the request (excluding the external call). Do not call this function, as it will have no practical effect." + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 3386, + "contract": "contracts/rrp/AirnodeRrpV0DryRun.sol:AirnodeRrpV0DryRun", + "label": "requestIdToFulfillmentParameters", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_bytes32)" + } + ], + "types": { + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_bytes32)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => bytes32)", + "numberOfBytes": "32", + "value": "t_bytes32" + } + } + } +} diff --git a/packages/airnode-protocol/deployments/lightlink-goerli-testnet/RequesterAuthorizerWithAirnode.json b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/RequesterAuthorizerWithAirnode.json new file mode 100644 index 0000000000..212d628d33 --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/RequesterAuthorizerWithAirnode.json @@ -0,0 +1,912 @@ +{ + "address": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_accessControlRegistry", + "type": "address" + }, + { + "internalType": "string", + "name": "_adminRoleDescription", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + } + ], + "name": "ExtendedWhitelistExpiration", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "setter", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint192", + "name": "indefiniteWhitelistCount", + "type": "uint192" + } + ], + "name": "RevokedIndefiniteWhitelistStatus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint192", + "name": "indefiniteWhitelistCount", + "type": "uint192" + } + ], + "name": "SetIndefiniteWhitelistStatus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + } + ], + "name": "SetWhitelistExpiration", + "type": "event" + }, + { + "inputs": [], + "name": "INDEFINITE_WHITELISTER_ROLE_DESCRIPTION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlRegistry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "adminRoleDescription", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "address", + "name": "setter", + "type": "address" + } + ], + "name": "airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus", + "outputs": [ + { + "internalType": "bool", + "name": "indefiniteWhitelistStatus", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + } + ], + "name": "airnodeToEndpointIdToRequesterToWhitelistStatus", + "outputs": [ + { + "internalType": "uint64", + "name": "expirationTimestamp", + "type": "uint64" + }, + { + "internalType": "uint192", + "name": "indefiniteWhitelistCount", + "type": "uint192" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + } + ], + "name": "deriveAdminRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + } + ], + "name": "deriveIndefiniteWhitelisterRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "indefiniteWhitelisterRole", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + } + ], + "name": "deriveWhitelistExpirationExtenderRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "whitelistExpirationExtenderRole", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + } + ], + "name": "deriveWhitelistExpirationSetterRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "whitelistExpirationSetterRole", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "uint64", + "name": "expirationTimestamp", + "type": "uint64" + } + ], + "name": "extendWhitelistExpiration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + } + ], + "name": "isAuthorized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + } + ], + "name": "isAuthorizedV0", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "address", + "name": "setter", + "type": "address" + } + ], + "name": "revokeIndefiniteWhitelistStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "setIndefiniteWhitelistStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "uint64", + "name": "expirationTimestamp", + "type": "uint64" + } + ], + "name": "setWhitelistExpiration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0xa9511ffbb4d2b61fa4666363b45c12cc3dd08d80a857251ecabb46f5b821414e", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xc97965EbD0f2123Cc31BEc63E18A8Ce9Ef6a1e7e", + "contractAddress": "0x0000000000000000000000000000000000000000", + "transactionIndex": 0, + "gasUsed": "1571034", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x540d9db4f314d462cd4a456d94fe7471b8643175241832ca2081acda80be6df8", + "transactionHash": "0xa9511ffbb4d2b61fa4666363b45c12cc3dd08d80a857251ecabb46f5b821414e", + "logs": [], + "blockNumber": 56898233, + "cumulativeGasUsed": "1571034", + "status": 1, + "byzantium": true + }, + "args": ["0x92E5125adF385d86beDb950793526106143b6Df1", "RequesterAuthorizerWithAirnode admin"], + "numDeployments": 1, + "solcInputHash": "d8591a026515856ab7bc7dc284bf2fbe", + "metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_accessControlRegistry\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_adminRoleDescription\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"ExtendedWhitelistExpiration\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"setter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"indefiniteWhitelistCount\",\"type\":\"uint192\"}],\"name\":\"RevokedIndefiniteWhitelistStatus\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"indefiniteWhitelistCount\",\"type\":\"uint192\"}],\"name\":\"SetIndefiniteWhitelistStatus\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"SetWhitelistExpiration\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"INDEFINITE_WHITELISTER_ROLE_DESCRIPTION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"accessControlRegistry\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"adminRoleDescription\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"setter\",\"type\":\"address\"}],\"name\":\"airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"indefiniteWhitelistStatus\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"name\":\"airnodeToEndpointIdToRequesterToWhitelistStatus\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"expirationTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"uint192\",\"name\":\"indefiniteWhitelistCount\",\"type\":\"uint192\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"}],\"name\":\"deriveAdminRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"adminRole\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"}],\"name\":\"deriveIndefiniteWhitelisterRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"indefiniteWhitelisterRole\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"}],\"name\":\"deriveWhitelistExpirationExtenderRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"whitelistExpirationExtenderRole\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"}],\"name\":\"deriveWhitelistExpirationSetterRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"whitelistExpirationSetterRole\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"expirationTimestamp\",\"type\":\"uint64\"}],\"name\":\"extendWhitelistExpiration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"name\":\"isAuthorized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"name\":\"isAuthorizedV0\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"setter\",\"type\":\"address\"}],\"name\":\"revokeIndefiniteWhitelistStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"setIndefiniteWhitelistStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"expirationTimestamp\",\"type\":\"uint64\"}],\"name\":\"setWhitelistExpiration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(address,bytes32,address,address)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requester\":\"Requester address\",\"setter\":\"Address of the account that has potentially whitelisted `requester` for the `airnode`\\u2013`endpointId` pair indefinitely\"},\"returns\":{\"indefiniteWhitelistStatus\":\"If `setter` has indefinitely whitelisted `requester` for the `airnode`\\u2013`endpointId` pair\"}},\"airnodeToEndpointIdToRequesterToWhitelistStatus(address,bytes32,address)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requester\":\"Requester address\"},\"returns\":{\"expirationTimestamp\":\"Timestamp at which the temporary whitelist will expire\",\"indefiniteWhitelistCount\":\"Number of times `requester` was whitelisted indefinitely for the `airnode`\\u2013`endpointId` pair\"}},\"constructor\":{\"params\":{\"_accessControlRegistry\":\"AccessControlRegistry contract address\",\"_adminRoleDescription\":\"Admin role description\"}},\"deriveAdminRole(address)\":{\"params\":{\"airnode\":\"Airnode address\"},\"returns\":{\"adminRole\":\"Admin role\"}},\"deriveIndefiniteWhitelisterRole(address)\":{\"params\":{\"airnode\":\"Airnode address\"},\"returns\":{\"indefiniteWhitelisterRole\":\"Indefinite whitelister role\"}},\"deriveWhitelistExpirationExtenderRole(address)\":{\"params\":{\"airnode\":\"Airnode address\"},\"returns\":{\"whitelistExpirationExtenderRole\":\"Whitelist expiration extender role\"}},\"deriveWhitelistExpirationSetterRole(address)\":{\"params\":{\"airnode\":\"Airnode address\"},\"returns\":{\"whitelistExpirationSetterRole\":\"Whitelist expiration setter role\"}},\"extendWhitelistExpiration(address,bytes32,address,uint64)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"expirationTimestamp\":\"Timestamp at which the temporary whitelist will expire\",\"requester\":\"Requester address\"}},\"isAuthorized(address,bytes32,address)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requester\":\"Requester address\"},\"returns\":{\"_0\":\"Authorization status of the request\"}},\"isAuthorizedV0(bytes32,address,bytes32,address,address)\":{\"details\":\"This method has redundant arguments because V0 authorizer contracts have to have the same interface and potential authorizer contracts may require to access the arguments that are redundant here\",\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requestId\":\"Request ID\",\"requester\":\"Requester address\",\"sponsor\":\"Sponsor address\"},\"returns\":{\"_0\":\"Authorization status of the request\"}},\"multicall(bytes[])\":{\"details\":\"Receives and executes a batch of function calls on this contract.\"},\"revokeIndefiniteWhitelistStatus(address,bytes32,address,address)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requester\":\"Requester address\",\"setter\":\"Setter of the indefinite whitelist status\"}},\"setIndefiniteWhitelistStatus(address,bytes32,address,bool)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requester\":\"Requester address\",\"status\":\"Indefinite whitelist status\"}},\"setWhitelistExpiration(address,bytes32,address,uint64)\":{\"details\":\"Unlike `extendWhitelistExpiration()`, this can hasten expiration\",\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"expirationTimestamp\":\"Timestamp at which the temporary whitelist will expire\",\"requester\":\"Requester address\"}}},\"title\":\"Authorizer contract that Airnode operators can use to temporarily or indefinitely whitelist requesters for Airnode\\u2013endpoint pairs\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"INDEFINITE_WHITELISTER_ROLE_DESCRIPTION()\":{\"notice\":\"Indefinite whitelister role description\"},\"WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION()\":{\"notice\":\"Whitelist expiration extender role description\"},\"WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION()\":{\"notice\":\"Whitelist expiration setter role description\"},\"accessControlRegistry()\":{\"notice\":\"AccessControlRegistry contract address\"},\"adminRoleDescription()\":{\"notice\":\"Admin role description\"},\"airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(address,bytes32,address,address)\":{\"notice\":\"Returns if an account has indefinitely whitelisted `requester` for the `airnode`\\u2013`endpointId` pair\"},\"airnodeToEndpointIdToRequesterToWhitelistStatus(address,bytes32,address)\":{\"notice\":\"Returns the whitelist status of `requester` for the `airnode`\\u2013`endpointId` pair\"},\"deriveAdminRole(address)\":{\"notice\":\"Derives the admin role for the Airnode\"},\"deriveIndefiniteWhitelisterRole(address)\":{\"notice\":\"Derives the indefinite whitelister role for the Airnode\"},\"deriveWhitelistExpirationExtenderRole(address)\":{\"notice\":\"Derives the whitelist expiration extender role for the Airnode\"},\"deriveWhitelistExpirationSetterRole(address)\":{\"notice\":\"Derives the whitelist expiration setter role for the Airnode\"},\"extendWhitelistExpiration(address,bytes32,address,uint64)\":{\"notice\":\"Extends the expiration of the temporary whitelist of `requester` for the `airnode`\\u2013`endpointId` pair if the sender has the whitelist expiration extender role\"},\"isAuthorized(address,bytes32,address)\":{\"notice\":\"Verifies the authorization status of a request\"},\"isAuthorizedV0(bytes32,address,bytes32,address,address)\":{\"notice\":\"Verifies the authorization status of a request\"},\"revokeIndefiniteWhitelistStatus(address,bytes32,address,address)\":{\"notice\":\"Revokes the indefinite whitelist status granted by a specific account that no longer has the indefinite whitelister role\"},\"setIndefiniteWhitelistStatus(address,bytes32,address,bool)\":{\"notice\":\"Sets the indefinite whitelist status of `requester` for the `airnode`\\u2013`endpointId` pair if the sender has the indefinite whitelister role\"},\"setWhitelistExpiration(address,bytes32,address,uint64)\":{\"notice\":\"Sets the expiration of the temporary whitelist of `requester` for the `airnode`\\u2013`endpointId` pair if the sender has the whitelist expiration setter role\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/authorizers/RequesterAuthorizerWithAirnode.sol\":\"RequesterAuthorizerWithAirnode\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\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 * _Available since v3.1._\\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 `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Multicall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Multicall.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @dev Provides a function to batch together multiple calls in a single external call.\\n *\\n * _Available since v4.1._\\n */\\nabstract contract Multicall {\\n /**\\n * @dev Receives and executes a batch of function calls on this contract.\\n */\\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n results[i] = Address.functionDelegateCall(address(this), data[i]);\\n }\\n return results;\\n }\\n}\\n\",\"keccak256\":\"0x768ccb0d556d2edde43cf5fc16860a936ce91eca96be0cf9e807ffe875f6f516\",\"license\":\"MIT\"},\"contracts/access-control-registry/AccessControlRegistryAdminned.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Multicall.sol\\\";\\nimport \\\"./RoleDeriver.sol\\\";\\nimport \\\"./AccessControlRegistryUser.sol\\\";\\nimport \\\"./interfaces/IAccessControlRegistryAdminned.sol\\\";\\n\\n/// @title Contract to be inherited by contracts whose adminship functionality\\n/// will be implemented using AccessControlRegistry\\ncontract AccessControlRegistryAdminned is\\n Multicall,\\n RoleDeriver,\\n AccessControlRegistryUser,\\n IAccessControlRegistryAdminned\\n{\\n /// @notice Admin role description\\n string public override adminRoleDescription;\\n\\n bytes32 internal immutable adminRoleDescriptionHash;\\n\\n /// @dev Contracts deployed with the same admin role descriptions will have\\n /// the same roles, meaning that granting an account a role will authorize\\n /// it in multiple contracts. Unless you want your deployed contract to\\n /// share the role configuration of another contract, use a unique admin\\n /// role description.\\n /// @param _accessControlRegistry AccessControlRegistry contract address\\n /// @param _adminRoleDescription Admin role description\\n constructor(\\n address _accessControlRegistry,\\n string memory _adminRoleDescription\\n ) AccessControlRegistryUser(_accessControlRegistry) {\\n require(\\n bytes(_adminRoleDescription).length > 0,\\n \\\"Admin role description empty\\\"\\n );\\n adminRoleDescription = _adminRoleDescription;\\n adminRoleDescriptionHash = keccak256(\\n abi.encodePacked(_adminRoleDescription)\\n );\\n }\\n\\n /// @notice Derives the admin role for the specific manager address\\n /// @param manager Manager address\\n /// @return adminRole Admin role\\n function _deriveAdminRole(address manager)\\n internal\\n view\\n returns (bytes32 adminRole)\\n {\\n adminRole = _deriveRole(\\n _deriveRootRole(manager),\\n adminRoleDescriptionHash\\n );\\n }\\n}\\n\",\"keccak256\":\"0xf09ba7f972b6bc37041596f5fd8757192fe1c63009b75752dc6f57b4eb4bb6cd\",\"license\":\"MIT\"},\"contracts/access-control-registry/AccessControlRegistryUser.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/IAccessControlRegistry.sol\\\";\\nimport \\\"./interfaces/IAccessControlRegistryUser.sol\\\";\\n\\n/// @title Contract to be inherited by contracts that will interact with\\n/// AccessControlRegistry\\ncontract AccessControlRegistryUser is IAccessControlRegistryUser {\\n /// @notice AccessControlRegistry contract address\\n address public immutable override accessControlRegistry;\\n\\n /// @param _accessControlRegistry AccessControlRegistry contract address\\n constructor(address _accessControlRegistry) {\\n require(_accessControlRegistry != address(0), \\\"ACR address zero\\\");\\n accessControlRegistry = _accessControlRegistry;\\n }\\n}\\n\",\"keccak256\":\"0x43744b38d8d71226bc8fb80942d5444a50cd1255f3bded0aee390f897d142802\",\"license\":\"MIT\"},\"contracts/access-control-registry/RoleDeriver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @title Contract to be inherited by contracts that will derive\\n/// AccessControlRegistry roles\\n/// @notice If a contract interfaces with AccessControlRegistry and needs to\\n/// derive roles, it should inherit this contract instead of re-implementing\\n/// the logic\\ncontract RoleDeriver {\\n /// @notice Derives the root role of the manager\\n /// @param manager Manager address\\n /// @return rootRole Root role\\n function _deriveRootRole(address manager)\\n internal\\n pure\\n returns (bytes32 rootRole)\\n {\\n rootRole = keccak256(abi.encodePacked(manager));\\n }\\n\\n /// @notice Derives the role using its admin role and description\\n /// @dev This implies that roles adminned by the same role cannot have the\\n /// same description\\n /// @param adminRole Admin role\\n /// @param description Human-readable description of the role\\n /// @return role Role\\n function _deriveRole(bytes32 adminRole, string memory description)\\n internal\\n pure\\n returns (bytes32 role)\\n {\\n role = _deriveRole(adminRole, keccak256(abi.encodePacked(description)));\\n }\\n\\n /// @notice Derives the role using its admin role and description hash\\n /// @dev This implies that roles adminned by the same role cannot have the\\n /// same description\\n /// @param adminRole Admin role\\n /// @param descriptionHash Hash of the human-readable description of the\\n /// role\\n /// @return role Role\\n function _deriveRole(bytes32 adminRole, bytes32 descriptionHash)\\n internal\\n pure\\n returns (bytes32 role)\\n {\\n role = keccak256(abi.encodePacked(adminRole, descriptionHash));\\n }\\n}\\n\",\"keccak256\":\"0x20fe9d6cce9a1e4fe0b5bd8868fabbe6ee9db7fa8154bcf6316005307d63ee04\",\"license\":\"MIT\"},\"contracts/access-control-registry/interfaces/IAccessControlRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/IAccessControl.sol\\\";\\n\\ninterface IAccessControlRegistry is IAccessControl {\\n event InitializedManager(bytes32 indexed rootRole, address indexed manager);\\n\\n event InitializedRole(\\n bytes32 indexed role,\\n bytes32 indexed adminRole,\\n string description,\\n address sender\\n );\\n\\n function initializeManager(address manager) external;\\n\\n function initializeRoleAndGrantToSender(\\n bytes32 adminRole,\\n string calldata description\\n ) external returns (bytes32 role);\\n\\n function deriveRootRole(address manager)\\n external\\n pure\\n returns (bytes32 rootRole);\\n\\n function deriveRole(bytes32 adminRole, string calldata description)\\n external\\n pure\\n returns (bytes32 role);\\n}\\n\",\"keccak256\":\"0x51b6c37b03f81667920dac10d53efc75e403c11348e71311b39a25c9b1cfdf76\",\"license\":\"MIT\"},\"contracts/access-control-registry/interfaces/IAccessControlRegistryAdminned.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControlRegistryUser.sol\\\";\\n\\ninterface IAccessControlRegistryAdminned is IAccessControlRegistryUser {\\n function adminRoleDescription() external view returns (string memory);\\n}\\n\",\"keccak256\":\"0x0f3ad45d6e1a4815cfaff171926ad5352d499a431b041b11adb316f4569bcce4\",\"license\":\"MIT\"},\"contracts/access-control-registry/interfaces/IAccessControlRegistryUser.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IAccessControlRegistryUser {\\n function accessControlRegistry() external view returns (address);\\n}\\n\",\"keccak256\":\"0xce1ceb04823a801ea173fe5140344645295768ff1b4d2ee2969c2f4b362102ca\",\"license\":\"MIT\"},\"contracts/authorizers/RequesterAuthorizer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"../whitelist/Whitelist.sol\\\";\\nimport \\\"./interfaces/IRequesterAuthorizer.sol\\\";\\n\\n/// @title Abstract contract to be inherited by Authorizer contracts that\\n/// temporarily or permanently whitelist requesters for Airnode\\u2013endpoint pairs\\nabstract contract RequesterAuthorizer is Whitelist, IRequesterAuthorizer {\\n /// @notice Extends the expiration of the temporary whitelist of\\n /// `requester` for the `airnode`\\u2013`endpointId` pair and emits an event\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param requester Requester address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function _extendWhitelistExpirationAndEmit(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) internal {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n require(requester != address(0), \\\"Requester address zero\\\");\\n _extendWhitelistExpiration(\\n deriveServiceId(airnode, endpointId),\\n requester,\\n expirationTimestamp\\n );\\n emit ExtendedWhitelistExpiration(\\n airnode,\\n endpointId,\\n requester,\\n msg.sender,\\n expirationTimestamp\\n );\\n }\\n\\n /// @notice Sets the expiration of the temporary whitelist of `requester`\\n /// for the `airnode`\\u2013`endpointId` pair and emits an event\\n /// @dev Unlike `_extendWhitelistExpiration()`, this can hasten expiration\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param requester Requester address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function _setWhitelistExpirationAndEmit(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) internal {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n require(requester != address(0), \\\"Requester address zero\\\");\\n _setWhitelistExpiration(\\n deriveServiceId(airnode, endpointId),\\n requester,\\n expirationTimestamp\\n );\\n emit SetWhitelistExpiration(\\n airnode,\\n endpointId,\\n requester,\\n msg.sender,\\n expirationTimestamp\\n );\\n }\\n\\n /// @notice Sets the indefinite whitelist status of `requester` for the\\n /// `airnode`\\u2013`endpointId` pair and emits an event\\n /// @dev Emits the event even if it does not change the state.\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param requester Requester address\\n /// @param status Indefinite whitelist status\\n function _setIndefiniteWhitelistStatusAndEmit(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n bool status\\n ) internal {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n require(requester != address(0), \\\"Requester address zero\\\");\\n uint192 indefiniteWhitelistCount = _setIndefiniteWhitelistStatus(\\n deriveServiceId(airnode, endpointId),\\n requester,\\n status\\n );\\n emit SetIndefiniteWhitelistStatus(\\n airnode,\\n endpointId,\\n requester,\\n msg.sender,\\n status,\\n indefiniteWhitelistCount\\n );\\n }\\n\\n /// @notice Revokes the indefinite whitelist status granted to `requester`\\n /// for the `airnode`\\u2013`endpointId` pair by a specific account and emits an\\n /// event\\n /// @dev Only emits the event if it changes the state\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param requester Requester address\\n /// @param setter Setter of the indefinite whitelist status\\n function _revokeIndefiniteWhitelistStatusAndEmit(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n address setter\\n ) internal {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n require(requester != address(0), \\\"Requester address zero\\\");\\n require(setter != address(0), \\\"Setter address zero\\\");\\n (\\n bool revoked,\\n uint192 indefiniteWhitelistCount\\n ) = _revokeIndefiniteWhitelistStatus(\\n deriveServiceId(airnode, endpointId),\\n requester,\\n setter\\n );\\n if (revoked) {\\n emit RevokedIndefiniteWhitelistStatus(\\n airnode,\\n endpointId,\\n requester,\\n setter,\\n msg.sender,\\n indefiniteWhitelistCount\\n );\\n }\\n }\\n\\n /// @notice Verifies the authorization status of a request\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @return Authorization status of the request\\n function isAuthorized(\\n address airnode,\\n bytes32 endpointId,\\n address requester\\n ) external view override returns (bool) {\\n return\\n userIsWhitelisted(deriveServiceId(airnode, endpointId), requester);\\n }\\n\\n /// @notice Verifies the authorization status of a request\\n /// @dev This method has redundant arguments because V0 authorizer\\n /// contracts have to have the same interface and potential authorizer\\n /// contracts may require to access the arguments that are redundant here\\n /// @param requestId Request ID\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param sponsor Sponsor address\\n /// @param requester Requester address\\n /// @return Authorization status of the request\\n function isAuthorizedV0(\\n bytes32 requestId, // solhint-disable-line no-unused-vars\\n address airnode,\\n bytes32 endpointId,\\n address sponsor, // solhint-disable-line no-unused-vars\\n address requester\\n ) external view override returns (bool) {\\n return\\n userIsWhitelisted(deriveServiceId(airnode, endpointId), requester);\\n }\\n\\n /// @notice Returns the whitelist status of `requester` for the\\n /// `airnode`\\u2013`endpointId` pair\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @return expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n /// @return indefiniteWhitelistCount Number of times `requester` was\\n /// whitelisted indefinitely for the `airnode`\\u2013`endpointId` pair\\n function airnodeToEndpointIdToRequesterToWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester\\n )\\n external\\n view\\n override\\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount)\\n {\\n WhitelistStatus\\n storage whitelistStatus = serviceIdToUserToWhitelistStatus[\\n deriveServiceId(airnode, endpointId)\\n ][requester];\\n expirationTimestamp = whitelistStatus.expirationTimestamp;\\n indefiniteWhitelistCount = whitelistStatus.indefiniteWhitelistCount;\\n }\\n\\n /// @notice Returns if an account has indefinitely whitelisted `requester`\\n /// for the `airnode`\\u2013`endpointId` pair\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @param setter Address of the account that has potentially whitelisted\\n /// `requester` for the `airnode`\\u2013`endpointId` pair indefinitely\\n /// @return indefiniteWhitelistStatus If `setter` has indefinitely\\n /// whitelisted `requester` for the `airnode`\\u2013`endpointId` pair\\n function airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n address setter\\n ) external view override returns (bool indefiniteWhitelistStatus) {\\n indefiniteWhitelistStatus = serviceIdToUserToSetterToIndefiniteWhitelistStatus[\\n deriveServiceId(airnode, endpointId)\\n ][requester][setter];\\n }\\n\\n /// @notice Called privately to derive a service ID out of the Airnode\\n /// address and the endpoint ID\\n /// @dev This is done to re-use the more general Whitelist contract for\\n /// the specific case of Airnode\\u2013endpoint pairs\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @return serviceId Service ID\\n function deriveServiceId(address airnode, bytes32 endpointId)\\n private\\n pure\\n returns (bytes32 serviceId)\\n {\\n serviceId = keccak256(abi.encodePacked(airnode, endpointId));\\n }\\n}\\n\",\"keccak256\":\"0x7b75fda3fd3e3aba6814a3baba32a429cdb0141f40cf5d0f4a0a8bf85171882a\",\"license\":\"MIT\"},\"contracts/authorizers/RequesterAuthorizerWithAirnode.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"../whitelist/WhitelistRolesWithAirnode.sol\\\";\\nimport \\\"./RequesterAuthorizer.sol\\\";\\nimport \\\"./interfaces/IRequesterAuthorizerWithAirnode.sol\\\";\\n\\n/// @title Authorizer contract that Airnode operators can use to temporarily or\\n/// indefinitely whitelist requesters for Airnode\\u2013endpoint pairs\\ncontract RequesterAuthorizerWithAirnode is\\n WhitelistRolesWithAirnode,\\n RequesterAuthorizer,\\n IRequesterAuthorizerWithAirnode\\n{\\n /// @param _accessControlRegistry AccessControlRegistry contract address\\n /// @param _adminRoleDescription Admin role description\\n constructor(\\n address _accessControlRegistry,\\n string memory _adminRoleDescription\\n )\\n WhitelistRolesWithAirnode(_accessControlRegistry, _adminRoleDescription)\\n {}\\n\\n /// @notice Extends the expiration of the temporary whitelist of\\n /// `requester` for the `airnode`\\u2013`endpointId` pair if the sender has the\\n /// whitelist expiration extender role\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function extendWhitelistExpiration(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) external override {\\n require(\\n hasWhitelistExpirationExtenderRoleOrIsAirnode(airnode, msg.sender),\\n \\\"Cannot extend expiration\\\"\\n );\\n _extendWhitelistExpirationAndEmit(\\n airnode,\\n endpointId,\\n requester,\\n expirationTimestamp\\n );\\n }\\n\\n /// @notice Sets the expiration of the temporary whitelist of `requester`\\n /// for the `airnode`\\u2013`endpointId` pair if the sender has the whitelist\\n /// expiration setter role\\n /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function setWhitelistExpiration(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) external override {\\n require(\\n hasWhitelistExpirationSetterRoleOrIsAirnode(airnode, msg.sender),\\n \\\"Cannot set expiration\\\"\\n );\\n _setWhitelistExpirationAndEmit(\\n airnode,\\n endpointId,\\n requester,\\n expirationTimestamp\\n );\\n }\\n\\n /// @notice Sets the indefinite whitelist status of `requester` for the\\n /// `airnode`\\u2013`endpointId` pair if the sender has the indefinite\\n /// whitelister role\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @param status Indefinite whitelist status\\n function setIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n bool status\\n ) external override {\\n require(\\n hasIndefiniteWhitelisterRoleOrIsAirnode(airnode, msg.sender),\\n \\\"Cannot set indefinite status\\\"\\n );\\n _setIndefiniteWhitelistStatusAndEmit(\\n airnode,\\n endpointId,\\n requester,\\n status\\n );\\n }\\n\\n /// @notice Revokes the indefinite whitelist status granted by a specific\\n /// account that no longer has the indefinite whitelister role\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @param setter Setter of the indefinite whitelist status\\n function revokeIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n address setter\\n ) external override {\\n require(\\n !hasIndefiniteWhitelisterRoleOrIsAirnode(airnode, setter),\\n \\\"setter can set indefinite status\\\"\\n );\\n _revokeIndefiniteWhitelistStatusAndEmit(\\n airnode,\\n endpointId,\\n requester,\\n setter\\n );\\n }\\n}\\n\",\"keccak256\":\"0xe54f7461125993102c504232e5a93bdca77703e95fcb99fcb1ed196e2f5e09d9\",\"license\":\"MIT\"},\"contracts/authorizers/interfaces/IAuthorizerV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IAuthorizerV0 {\\n function isAuthorizedV0(\\n bytes32 requestId,\\n address airnode,\\n bytes32 endpointId,\\n address sponsor,\\n address requester\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xa38872f5dead4dfc0c8075c245c10197df1ace09415f2e0d5b46bc8511cc3f6d\",\"license\":\"MIT\"},\"contracts/authorizers/interfaces/IRequesterAuthorizer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAuthorizerV0.sol\\\";\\n\\ninterface IRequesterAuthorizer is IAuthorizerV0 {\\n event ExtendedWhitelistExpiration(\\n address indexed airnode,\\n bytes32 endpointId,\\n address indexed requester,\\n address indexed sender,\\n uint256 expiration\\n );\\n\\n event SetWhitelistExpiration(\\n address indexed airnode,\\n bytes32 endpointId,\\n address indexed requester,\\n address indexed sender,\\n uint256 expiration\\n );\\n\\n event SetIndefiniteWhitelistStatus(\\n address indexed airnode,\\n bytes32 endpointId,\\n address indexed requester,\\n address indexed sender,\\n bool status,\\n uint192 indefiniteWhitelistCount\\n );\\n\\n event RevokedIndefiniteWhitelistStatus(\\n address indexed airnode,\\n bytes32 endpointId,\\n address indexed requester,\\n address indexed setter,\\n address sender,\\n uint192 indefiniteWhitelistCount\\n );\\n\\n function extendWhitelistExpiration(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) external;\\n\\n function setWhitelistExpiration(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) external;\\n\\n function setIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n bool status\\n ) external;\\n\\n function revokeIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n address setter\\n ) external;\\n\\n function airnodeToEndpointIdToRequesterToWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester\\n )\\n external\\n view\\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount);\\n\\n function airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n address setter\\n ) external view returns (bool indefiniteWhitelistStatus);\\n\\n function isAuthorized(\\n address airnode,\\n bytes32 endpointId,\\n address requester\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x2aecb3b19965b47a373e0bd346b8a626878cc7aa8e85a2156741f7154cd4ec60\",\"license\":\"MIT\"},\"contracts/authorizers/interfaces/IRequesterAuthorizerWithAirnode.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../whitelist/interfaces/IWhitelistRolesWithAirnode.sol\\\";\\nimport \\\"./IRequesterAuthorizer.sol\\\";\\n\\ninterface IRequesterAuthorizerWithAirnode is\\n IWhitelistRolesWithAirnode,\\n IRequesterAuthorizer\\n{}\\n\",\"keccak256\":\"0x5ea885c0792ab843a81ed5294e9edec8be0184aa4f84d51b8cdbe297d002b6e6\",\"license\":\"MIT\"},\"contracts/whitelist/Whitelist.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @title Contract to be inherited by contracts that need temporary and\\n/// permanent whitelists for services identified by hashes\\n/// @notice This contract implements two kinds of whitelisting:\\n/// (1) Temporary, ends when the expiration timestamp is in the past\\n/// (2) Indefinite, ends when the indefinite whitelist count is zero\\n/// Multiple senders can indefinitely whitelist/unwhitelist independently. The\\n/// user will be considered whitelisted as long as there is at least one active\\n/// indefinite whitelisting.\\n/// @dev The interface of this contract is not implemented. It should be\\n/// inherited and its functions should be exposed with a sort of an\\n/// authorization scheme.\\ncontract Whitelist {\\n struct WhitelistStatus {\\n uint64 expirationTimestamp;\\n uint192 indefiniteWhitelistCount;\\n }\\n\\n mapping(bytes32 => mapping(address => WhitelistStatus))\\n internal serviceIdToUserToWhitelistStatus;\\n\\n mapping(bytes32 => mapping(address => mapping(address => bool)))\\n internal serviceIdToUserToSetterToIndefiniteWhitelistStatus;\\n\\n /// @notice Extends the expiration of the temporary whitelist of the user\\n /// for the service\\n /// @param serviceId Service ID\\n /// @param user User address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function _extendWhitelistExpiration(\\n bytes32 serviceId,\\n address user,\\n uint64 expirationTimestamp\\n ) internal {\\n require(\\n expirationTimestamp >\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .expirationTimestamp,\\n \\\"Does not extend expiration\\\"\\n );\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .expirationTimestamp = expirationTimestamp;\\n }\\n\\n /// @notice Sets the expiration of the temporary whitelist of the user for\\n /// the service\\n /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration\\n /// @param serviceId Service ID\\n /// @param user User address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function _setWhitelistExpiration(\\n bytes32 serviceId,\\n address user,\\n uint64 expirationTimestamp\\n ) internal {\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .expirationTimestamp = expirationTimestamp;\\n }\\n\\n /// @notice Sets the indefinite whitelist status of the user for the\\n /// service\\n /// @dev As long as at least there is at least one account that has set the\\n /// indefinite whitelist status of the user for the service as true, the\\n /// user will be considered whitelisted\\n /// @param serviceId Service ID\\n /// @param user User address\\n /// @param status Indefinite whitelist status\\n function _setIndefiniteWhitelistStatus(\\n bytes32 serviceId,\\n address user,\\n bool status\\n ) internal returns (uint192 indefiniteWhitelistCount) {\\n indefiniteWhitelistCount = serviceIdToUserToWhitelistStatus[serviceId][\\n user\\n ].indefiniteWhitelistCount;\\n if (\\n status &&\\n !serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][\\n user\\n ][msg.sender]\\n ) {\\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\\n msg.sender\\n ] = true;\\n indefiniteWhitelistCount++;\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\\n } else if (\\n !status &&\\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\\n msg.sender\\n ]\\n ) {\\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\\n msg.sender\\n ] = false;\\n indefiniteWhitelistCount--;\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\\n }\\n }\\n\\n /// @notice Revokes the indefinite whitelist status granted to the user for\\n /// the service by a specific account\\n /// @param serviceId Service ID\\n /// @param user User address\\n /// @param setter Setter of the indefinite whitelist status\\n function _revokeIndefiniteWhitelistStatus(\\n bytes32 serviceId,\\n address user,\\n address setter\\n ) internal returns (bool revoked, uint192 indefiniteWhitelistCount) {\\n indefiniteWhitelistCount = serviceIdToUserToWhitelistStatus[serviceId][\\n user\\n ].indefiniteWhitelistCount;\\n if (\\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\\n setter\\n ]\\n ) {\\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\\n setter\\n ] = false;\\n indefiniteWhitelistCount--;\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\\n revoked = true;\\n }\\n }\\n\\n /// @notice Returns if the user is whitelised to use the service\\n /// @param serviceId Service ID\\n /// @param user User address\\n /// @return isWhitelisted If the user is whitelisted\\n function userIsWhitelisted(bytes32 serviceId, address user)\\n internal\\n view\\n returns (bool isWhitelisted)\\n {\\n WhitelistStatus\\n storage whitelistStatus = serviceIdToUserToWhitelistStatus[\\n serviceId\\n ][user];\\n return\\n whitelistStatus.indefiniteWhitelistCount > 0 ||\\n whitelistStatus.expirationTimestamp > block.timestamp;\\n }\\n}\\n\",\"keccak256\":\"0x22e3980c4144e2f57a115e51b05f1aeede12fe94fbeb538a287f02e9eff6be89\",\"license\":\"MIT\"},\"contracts/whitelist/WhitelistRoles.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/IWhitelistRoles.sol\\\";\\n\\n/// @title Contract to be inherited by Whitelist contracts that will use\\n/// generic AccessControlRegistry roles\\ncontract WhitelistRoles is IWhitelistRoles {\\n // There are four roles implemented in this contract:\\n // Root\\n // \\u2514\\u2500\\u2500 (1) Admin (can grant and revoke the roles below)\\n // \\u251c\\u2500\\u2500 (2) Whitelist expiration extender\\n // \\u251c\\u2500\\u2500 (3) Whitelist expiration setter\\n // \\u2514\\u2500\\u2500 (4) Indefinite whitelister\\n // Their IDs are derived from the descriptions below. Refer to\\n // AccessControlRegistry for more information.\\n // To clarify, the root role of the manager is the admin of (1), while (1)\\n // is the admin of (2), (3) and (4). So (1) is more of a \\\"contract admin\\\",\\n // while the `adminRole` used in AccessControl and AccessControlRegistry\\n // refers to a more general adminship relationship between roles.\\n\\n /// @notice Whitelist expiration extender role description\\n string\\n public constant\\n override WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION =\\n \\\"Whitelist expiration extender\\\";\\n\\n /// @notice Whitelist expiration setter role description\\n string\\n public constant\\n override WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION =\\n \\\"Whitelist expiration setter\\\";\\n\\n /// @notice Indefinite whitelister role description\\n\\n string public constant override INDEFINITE_WHITELISTER_ROLE_DESCRIPTION =\\n \\\"Indefinite whitelister\\\";\\n\\n bytes32\\n internal constant WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH =\\n keccak256(\\n abi.encodePacked(WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION)\\n );\\n\\n bytes32\\n internal constant WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH =\\n keccak256(\\n abi.encodePacked(WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION)\\n );\\n\\n bytes32 internal constant INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH =\\n keccak256(abi.encodePacked(INDEFINITE_WHITELISTER_ROLE_DESCRIPTION));\\n}\\n\",\"keccak256\":\"0x2d52cc38e7cc74630a9e268b527da5f091c4916d5e2f946a0f5f3e8a1a9debc3\",\"license\":\"MIT\"},\"contracts/whitelist/WhitelistRolesWithAirnode.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./WhitelistRoles.sol\\\";\\nimport \\\"../access-control-registry/AccessControlRegistryAdminned.sol\\\";\\nimport \\\"./interfaces/IWhitelistRolesWithAirnode.sol\\\";\\nimport \\\"../access-control-registry/interfaces/IAccessControlRegistry.sol\\\";\\n\\n/// @title Contract to be inherited by Whitelist contracts that will use\\n/// roles where each individual Airnode address is its own manager\\ncontract WhitelistRolesWithAirnode is\\n WhitelistRoles,\\n AccessControlRegistryAdminned,\\n IWhitelistRolesWithAirnode\\n{\\n /// @param _accessControlRegistry AccessControlRegistry contract address\\n /// @param _adminRoleDescription Admin role description\\n constructor(\\n address _accessControlRegistry,\\n string memory _adminRoleDescription\\n )\\n AccessControlRegistryAdminned(\\n _accessControlRegistry,\\n _adminRoleDescription\\n )\\n {}\\n\\n /// @notice Derives the admin role for the Airnode\\n /// @param airnode Airnode address\\n /// @return adminRole Admin role\\n function deriveAdminRole(address airnode)\\n external\\n view\\n override\\n returns (bytes32 adminRole)\\n {\\n adminRole = _deriveAdminRole(airnode);\\n }\\n\\n /// @notice Derives the whitelist expiration extender role for the Airnode\\n /// @param airnode Airnode address\\n /// @return whitelistExpirationExtenderRole Whitelist expiration extender\\n /// role\\n function deriveWhitelistExpirationExtenderRole(address airnode)\\n public\\n view\\n override\\n returns (bytes32 whitelistExpirationExtenderRole)\\n {\\n whitelistExpirationExtenderRole = _deriveRole(\\n _deriveAdminRole(airnode),\\n WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH\\n );\\n }\\n\\n /// @notice Derives the whitelist expiration setter role for the Airnode\\n /// @param airnode Airnode address\\n /// @return whitelistExpirationSetterRole Whitelist expiration setter role\\n function deriveWhitelistExpirationSetterRole(address airnode)\\n public\\n view\\n override\\n returns (bytes32 whitelistExpirationSetterRole)\\n {\\n whitelistExpirationSetterRole = _deriveRole(\\n _deriveAdminRole(airnode),\\n WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH\\n );\\n }\\n\\n /// @notice Derives the indefinite whitelister role for the Airnode\\n /// @param airnode Airnode address\\n /// @return indefiniteWhitelisterRole Indefinite whitelister role\\n function deriveIndefiniteWhitelisterRole(address airnode)\\n public\\n view\\n override\\n returns (bytes32 indefiniteWhitelisterRole)\\n {\\n indefiniteWhitelisterRole = _deriveRole(\\n _deriveAdminRole(airnode),\\n INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH\\n );\\n }\\n\\n /// @dev Returns if the account has the whitelist expiration extender role\\n /// or is the Airnode address\\n /// @param airnode Airnode address\\n /// @param account Account address\\n /// @return If the account has the whitelist extender role or is the\\n /// Airnode address\\n function hasWhitelistExpirationExtenderRoleOrIsAirnode(\\n address airnode,\\n address account\\n ) internal view returns (bool) {\\n return\\n airnode == account ||\\n IAccessControlRegistry(accessControlRegistry).hasRole(\\n deriveWhitelistExpirationExtenderRole(airnode),\\n account\\n );\\n }\\n\\n /// @dev Returns if the account has the whitelist expriation setter role or\\n /// is the Airnode address\\n /// @param airnode Airnode address\\n /// @param account Account address\\n /// @return If the account has the whitelist setter role or is the Airnode\\n /// address\\n function hasWhitelistExpirationSetterRoleOrIsAirnode(\\n address airnode,\\n address account\\n ) internal view returns (bool) {\\n return\\n airnode == account ||\\n IAccessControlRegistry(accessControlRegistry).hasRole(\\n deriveWhitelistExpirationSetterRole(airnode),\\n account\\n );\\n }\\n\\n /// @dev Returns if the account has the indefinite whitelister role or is the\\n /// Airnode address\\n /// @param airnode Airnode address\\n /// @param account Account address\\n /// @return If the account has the indefinite whitelister role or is the\\n /// Airnode addrss\\n function hasIndefiniteWhitelisterRoleOrIsAirnode(\\n address airnode,\\n address account\\n ) internal view returns (bool) {\\n return\\n airnode == account ||\\n IAccessControlRegistry(accessControlRegistry).hasRole(\\n deriveIndefiniteWhitelisterRole(airnode),\\n account\\n );\\n }\\n}\\n\",\"keccak256\":\"0xc6f268bcf4826e93c71352a0d4b7b8adae32895f560d8eba9ba6ed7b0a454e32\",\"license\":\"MIT\"},\"contracts/whitelist/interfaces/IWhitelistRoles.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IWhitelistRoles {\\n // solhint-disable-next-line func-name-mixedcase\\n function WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION()\\n external\\n view\\n returns (string memory);\\n\\n // solhint-disable-next-line func-name-mixedcase\\n function WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION()\\n external\\n view\\n returns (string memory);\\n\\n // solhint-disable-next-line func-name-mixedcase\\n function INDEFINITE_WHITELISTER_ROLE_DESCRIPTION()\\n external\\n view\\n returns (string memory);\\n}\\n\",\"keccak256\":\"0x1143190e909f6aa779e99d143fdb26a91e42d269814a0d76152d31418db39fbf\",\"license\":\"MIT\"},\"contracts/whitelist/interfaces/IWhitelistRolesWithAirnode.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IWhitelistRoles.sol\\\";\\nimport \\\"../../access-control-registry/interfaces/IAccessControlRegistryAdminned.sol\\\";\\n\\ninterface IWhitelistRolesWithAirnode is\\n IWhitelistRoles,\\n IAccessControlRegistryAdminned\\n{\\n function deriveAdminRole(address airnode)\\n external\\n view\\n returns (bytes32 role);\\n\\n function deriveWhitelistExpirationExtenderRole(address airnode)\\n external\\n view\\n returns (bytes32 role);\\n\\n function deriveWhitelistExpirationSetterRole(address airnode)\\n external\\n view\\n returns (bytes32 role);\\n\\n function deriveIndefiniteWhitelisterRole(address airnode)\\n external\\n view\\n returns (bytes32 role);\\n}\\n\",\"keccak256\":\"0x019f362313bde834e12b45eec821ab20e75e6e54b11de7a2df33b39d516e5d09\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60c06040523480156200001157600080fd5b5060405162001d8938038062001d89833981016040819052620000349162000224565b81818181816001600160a01b038116620000885760405162461bcd60e51b815260206004820152601060248201526f4143522061646472657373207a65726f60801b60448201526064015b60405180910390fd5b6001600160a01b03166080528051620000e45760405162461bcd60e51b815260206004820152601c60248201527f41646d696e20726f6c65206465736372697074696f6e20656d7074790000000060448201526064016200007f565b8051620000f990600090602084019062000135565b50806040516020016200010d9190620002ff565b60408051601f19818403018152919052805160209091012060a052506200035a945050505050565b82805462000143906200031d565b90600052602060002090601f016020900481019282620001675760008555620001b2565b82601f106200018257805160ff1916838001178555620001b2565b82800160010185558215620001b2579182015b82811115620001b257825182559160200191906001019062000195565b50620001c0929150620001c4565b5090565b5b80821115620001c05760008155600101620001c5565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200020e578181015183820152602001620001f4565b838111156200021e576000848401525b50505050565b600080604083850312156200023857600080fd5b82516001600160a01b03811681146200025057600080fd5b60208401519092506001600160401b03808211156200026e57600080fd5b818501915085601f8301126200028357600080fd5b815181811115620002985762000298620001db565b604051601f8201601f19908116603f01168101908382118183101715620002c357620002c3620001db565b81604052828152886020848701011115620002dd57600080fd5b620002f0836020830160208801620001f1565b80955050505050509250929050565b6000825162000313818460208701620001f1565b9190910192915050565b600181811c908216806200033257607f821691505b602082108114156200035457634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a0516119f4620003956000396000610d620152600081816101400152818161097801528181610b980152610dbd01526119f46000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80636db798f9116100b25780639caa101b11610081578063b6316d8811610066578063b6316d8814610332578063d55a42dd14610345578063f57a044a1461038157600080fd5b80639caa101b146102ff578063ac9650d81461031257600080fd5b80636db798f91461026257806373c0627e1461029e5780637e766bc1146102b157806382d229e3146102c457600080fd5b80634751c2e2116101095780634cffd606116100ee5780634cffd606146101f257806352300976146102135780636bd2bdd01461022657600080fd5b80634751c2e2146101ca5780634c8f1d8d146101dd57600080fd5b80631ce9ae071461013b578063216de27e1461017f57806329b915b3146101a257806343b64962146101b5575b600080fd5b6101627f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b61019261018d366004611540565b610394565b6040519015158152602001610176565b6101926101b036600461158d565b6103e1565b6101c86101c33660046115f5565b610400565b005b6101c86101d8366004611644565b61046d565b6101e56104cf565b60405161017691906116ed565b610205610200366004611700565b61055d565b604051908152602001610176565b610205610221366004611700565b61056e565b6101e56040518060400160405280601b81526020017f57686974656c6973742065787069726174696f6e20736574746572000000000081525081565b6101e56040518060400160405280601d81526020017f57686974656c6973742065787069726174696f6e20657874656e64657200000081525081565b6101c86102ac366004611644565b6105dd565b6101c86102bf366004611540565b61063f565b6102d76102d236600461171b565b6106a2565b6040805167ffffffffffffffff90931683526001600160c01b03909116602083015201610176565b61020561030d366004611700565b610706565b610325610320366004611757565b61075a565b60405161017691906117cc565b610205610340366004611700565b61084f565b6101e56040518060400160405280601681526020017f496e646566696e6974652077686974656c69737465720000000000000000000081525081565b61019261038f36600461171b565b6108a3565b6000600260006103a487876108bc565b8152602080820192909252604090810160009081206001600160a01b03968716825283528181209490951685529290525090205460ff1692915050565b60006103f66103f086866108bc565b83610904565b9695505050505050565b61040a8433610959565b61045b5760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f742073657420696e646566696e697465207374617475730000000060448201526064015b60405180910390fd5b61046784848484610a44565b50505050565b6104778433610b79565b6104c35760405162461bcd60e51b815260206004820152601560248201527f43616e6e6f74207365742065787069726174696f6e00000000000000000000006044820152606401610452565b61046784848484610bce565b600080546104dc9061182e565b80601f01602080910402602001604051908101604052809291908181526020018280546105089061182e565b80156105555780601f1061052a57610100808354040283529160200191610555565b820191906000526020600020905b81548152906001019060200180831161053857829003601f168201915b505050505081565b600061056882610d18565b92915050565b600061056861057c83610d18565b6040518060400160405280601d81526020017f57686974656c6973742065787069726174696f6e20657874656e6465720000008152506040516020016105c29190611869565b60405160208183030381529060405280519060200120610d82565b6105e78433610d9e565b6106335760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420657874656e642065787069726174696f6e00000000000000006044820152606401610452565b61046784848484610df3565b6106498482610959565b156106965760405162461bcd60e51b815260206004820181905260248201527f7365747465722063616e2073657420696e646566696e697465207374617475736044820152606401610452565b61046784848484610efb565b6000806000600160006106b588886108bc565b8152602080820192909252604090810160009081206001600160a01b03979097168152959091529093205467ffffffffffffffff811696600160401b9091046001600160c01b031695509350505050565b600061056861071483610d18565b6040518060400160405280601681526020017f496e646566696e6974652077686974656c6973746572000000000000000000008152506040516020016105c29190611869565b60608167ffffffffffffffff81111561077557610775611885565b6040519080825280602002602001820160405280156107a857816020015b60608152602001906001900390816107935790505b50905060005b8281101561084857610818308585848181106107cc576107cc61189b565b90506020028101906107de91906118b1565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061107992505050565b82828151811061082a5761082a61189b565b6020026020010181905250808061084090611915565b9150506107ae565b5092915050565b600061056861085d83610d18565b6040518060400160405280601b81526020017f57686974656c6973742065787069726174696f6e2073657474657200000000008152506040516020016105c29190611869565b60006108b26103f085856108bc565b90505b9392505050565b6040516bffffffffffffffffffffffff19606084901b166020820152603481018290526000906054015b60405160208183030381529060405280519060200120905092915050565b60008281526001602090815260408083206001600160a01b038516845290915281208054600160401b90046001600160c01b0316151580610951575080544267ffffffffffffffff909116115b949350505050565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae85610706565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815260048101919091526001600160a01b038516602482015260440160206040518083038186803b158015610a0c57600080fd5b505afa158015610a20573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b59190611930565b6001600160a01b038416610a915760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610ae75760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b6000610afd610af686866108bc565b848461109e565b9050336001600160a01b0316836001600160a01b0316866001600160a01b03167f13d4d6afcb6d196f753a522f275673066719bb13944bd021efd1fca4286df20d878686604051610b6a9392919092835290151560208301526001600160c01b0316604082015260600190565b60405180910390a45050505050565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae8561084f565b6001600160a01b038416610c1b5760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610c715760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b610cbd610c7e85856108bc565b60009081526001602090815260408083206001600160a01b03871684529091529020805467ffffffffffffffff191667ffffffffffffffff8416179055565b6040805184815267ffffffffffffffff8316602082015233916001600160a01b0385811692908816917f375ee45428e158031095010484fd6451af89c501c79d75e390da4e91eb480ce191015b60405180910390a450505050565b6000610568610d60836040516bffffffffffffffffffffffff19606083901b166020820152600090603401604051602081830303815290604052805190602001209050919050565b7f00000000000000000000000000000000000000000000000000000000000000005b60408051602081018490529081018290526000906060016108e6565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae8561056e565b6001600160a01b038416610e405760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610e965760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b610eaa610ea385856108bc565b83836112a2565b6040805184815267ffffffffffffffff8316602082015233916001600160a01b0385811692908816917ff9b174be67f83278d4516865d1b9ba4576b73e523ea0c2f124ea29152bb1b6769101610d0a565b6001600160a01b038416610f485760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610f9e5760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b6001600160a01b038116610ff45760405162461bcd60e51b815260206004820152601360248201527f5365747465722061646472657373207a65726f000000000000000000000000006044820152606401610452565b60008061100b61100487876108bc565b8585611321565b91509150811561107157604080518681523360208201526001600160c01b0383168183015290516001600160a01b038581169287821692918a16917fdca622020d204c36e9588e7be4184758283d992606ab73318776824b44e2859d9181900360600190a45b505050505050565b60606108b583836040518060600160405280602781526020016119986027913961140f565b60008381526001602090815260408083206001600160a01b0386168452909152902054600160401b90046001600160c01b0316818015611109575060008481526002602090815260408083206001600160a01b0387168452825280832033845290915290205460ff16155b156111975760008481526002602090815260408083206001600160a01b038716845282528083203384529091529020805460ff191660011790558061114d8161194d565b60008681526001602090815260408083206001600160a01b03891684529091529020805467ffffffffffffffff16600160401b6001600160c01b0384160217905591506108b59050565b811580156111cf575060008481526002602090815260408083206001600160a01b0387168452825280832033845290915290205460ff165b156108b55760008481526002602090815260408083206001600160a01b038716845282528083203384529091529020805460ff191690558061121081611974565b60008681526001602090815260408083206001600160a01b0389168452909152902080546001600160c01b038316600160401b0267ffffffffffffffff9091161790559150509392505050565b60009283526001602090815260408085206001600160a01b039490941685529290529120805467ffffffffffffffff191667ffffffffffffffff909216919091179055565b60008381526001602090815260408083206001600160a01b038616845290915290205467ffffffffffffffff9081169082161161125d5760405162461bcd60e51b815260206004820152601a60248201527f446f6573206e6f7420657874656e642065787069726174696f6e0000000000006044820152606401610452565b60008381526001602090815260408083206001600160a01b0386811680865291845282852054888652600285528386209286529184528285209086168552909252822054600160401b9091046001600160c01b03169060ff16156114075760008581526002602090815260408083206001600160a01b03808916855290835281842090871684529091529020805460ff19169055806113bf81611974565b60008781526001602081815260408084206001600160a01b038b168552909152909120805467ffffffffffffffff16600160401b6001600160c01b0385160217905593509150505b935093915050565b6060833b6114855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610452565b600080856001600160a01b0316856040516114a09190611869565b600060405180830381855af49150503d80600081146114db576040519150601f19603f3d011682016040523d82523d6000602084013e6114e0565b606091505b50915091506103f6828286606083156114fa5750816108b5565b82511561150a5782518084602001fd5b8160405162461bcd60e51b815260040161045291906116ed565b80356001600160a01b038116811461153b57600080fd5b919050565b6000806000806080858703121561155657600080fd5b61155f85611524565b93506020850135925061157460408601611524565b915061158260608601611524565b905092959194509250565b600080600080600060a086880312156115a557600080fd5b853594506115b560208701611524565b9350604086013592506115ca60608701611524565b91506115d860808701611524565b90509295509295909350565b80151581146115f257600080fd5b50565b6000806000806080858703121561160b57600080fd5b61161485611524565b93506020850135925061162960408601611524565b91506060850135611639816115e4565b939692955090935050565b6000806000806080858703121561165a57600080fd5b61166385611524565b93506020850135925061167860408601611524565b9150606085013567ffffffffffffffff8116811461163957600080fd5b60005b838110156116b0578181015183820152602001611698565b838111156104675750506000910152565b600081518084526116d9816020860160208601611695565b601f01601f19169290920160200192915050565b6020815260006108b560208301846116c1565b60006020828403121561171257600080fd5b6108b582611524565b60008060006060848603121561173057600080fd5b61173984611524565b92506020840135915061174e60408501611524565b90509250925092565b6000806020838503121561176a57600080fd5b823567ffffffffffffffff8082111561178257600080fd5b818501915085601f83011261179657600080fd5b8135818111156117a557600080fd5b8660208260051b85010111156117ba57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561182157603f1988860301845261180f8583516116c1565b945092850192908501906001016117f3565b5092979650505050505050565b600181811c9082168061184257607f821691505b6020821081141561186357634e487b7160e01b600052602260045260246000fd5b50919050565b6000825161187b818460208701611695565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126118c857600080fd5b83018035915067ffffffffffffffff8211156118e357600080fd5b6020019150368190038213156118f857600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415611929576119296118ff565b5060010190565b60006020828403121561194257600080fd5b81516108b5816115e4565b60006001600160c01b038083168181141561196a5761196a6118ff565b6001019392505050565b60006001600160c01b0382168061198d5761198d6118ff565b600019019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122054c83dd126c12b6928fd970d1f434b676ba73e23c3efdfdac1ccc90a37703ce164736f6c63430008090033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101365760003560e01c80636db798f9116100b25780639caa101b11610081578063b6316d8811610066578063b6316d8814610332578063d55a42dd14610345578063f57a044a1461038157600080fd5b80639caa101b146102ff578063ac9650d81461031257600080fd5b80636db798f91461026257806373c0627e1461029e5780637e766bc1146102b157806382d229e3146102c457600080fd5b80634751c2e2116101095780634cffd606116100ee5780634cffd606146101f257806352300976146102135780636bd2bdd01461022657600080fd5b80634751c2e2146101ca5780634c8f1d8d146101dd57600080fd5b80631ce9ae071461013b578063216de27e1461017f57806329b915b3146101a257806343b64962146101b5575b600080fd5b6101627f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b61019261018d366004611540565b610394565b6040519015158152602001610176565b6101926101b036600461158d565b6103e1565b6101c86101c33660046115f5565b610400565b005b6101c86101d8366004611644565b61046d565b6101e56104cf565b60405161017691906116ed565b610205610200366004611700565b61055d565b604051908152602001610176565b610205610221366004611700565b61056e565b6101e56040518060400160405280601b81526020017f57686974656c6973742065787069726174696f6e20736574746572000000000081525081565b6101e56040518060400160405280601d81526020017f57686974656c6973742065787069726174696f6e20657874656e64657200000081525081565b6101c86102ac366004611644565b6105dd565b6101c86102bf366004611540565b61063f565b6102d76102d236600461171b565b6106a2565b6040805167ffffffffffffffff90931683526001600160c01b03909116602083015201610176565b61020561030d366004611700565b610706565b610325610320366004611757565b61075a565b60405161017691906117cc565b610205610340366004611700565b61084f565b6101e56040518060400160405280601681526020017f496e646566696e6974652077686974656c69737465720000000000000000000081525081565b61019261038f36600461171b565b6108a3565b6000600260006103a487876108bc565b8152602080820192909252604090810160009081206001600160a01b03968716825283528181209490951685529290525090205460ff1692915050565b60006103f66103f086866108bc565b83610904565b9695505050505050565b61040a8433610959565b61045b5760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f742073657420696e646566696e697465207374617475730000000060448201526064015b60405180910390fd5b61046784848484610a44565b50505050565b6104778433610b79565b6104c35760405162461bcd60e51b815260206004820152601560248201527f43616e6e6f74207365742065787069726174696f6e00000000000000000000006044820152606401610452565b61046784848484610bce565b600080546104dc9061182e565b80601f01602080910402602001604051908101604052809291908181526020018280546105089061182e565b80156105555780601f1061052a57610100808354040283529160200191610555565b820191906000526020600020905b81548152906001019060200180831161053857829003601f168201915b505050505081565b600061056882610d18565b92915050565b600061056861057c83610d18565b6040518060400160405280601d81526020017f57686974656c6973742065787069726174696f6e20657874656e6465720000008152506040516020016105c29190611869565b60405160208183030381529060405280519060200120610d82565b6105e78433610d9e565b6106335760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420657874656e642065787069726174696f6e00000000000000006044820152606401610452565b61046784848484610df3565b6106498482610959565b156106965760405162461bcd60e51b815260206004820181905260248201527f7365747465722063616e2073657420696e646566696e697465207374617475736044820152606401610452565b61046784848484610efb565b6000806000600160006106b588886108bc565b8152602080820192909252604090810160009081206001600160a01b03979097168152959091529093205467ffffffffffffffff811696600160401b9091046001600160c01b031695509350505050565b600061056861071483610d18565b6040518060400160405280601681526020017f496e646566696e6974652077686974656c6973746572000000000000000000008152506040516020016105c29190611869565b60608167ffffffffffffffff81111561077557610775611885565b6040519080825280602002602001820160405280156107a857816020015b60608152602001906001900390816107935790505b50905060005b8281101561084857610818308585848181106107cc576107cc61189b565b90506020028101906107de91906118b1565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061107992505050565b82828151811061082a5761082a61189b565b6020026020010181905250808061084090611915565b9150506107ae565b5092915050565b600061056861085d83610d18565b6040518060400160405280601b81526020017f57686974656c6973742065787069726174696f6e2073657474657200000000008152506040516020016105c29190611869565b60006108b26103f085856108bc565b90505b9392505050565b6040516bffffffffffffffffffffffff19606084901b166020820152603481018290526000906054015b60405160208183030381529060405280519060200120905092915050565b60008281526001602090815260408083206001600160a01b038516845290915281208054600160401b90046001600160c01b0316151580610951575080544267ffffffffffffffff909116115b949350505050565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae85610706565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815260048101919091526001600160a01b038516602482015260440160206040518083038186803b158015610a0c57600080fd5b505afa158015610a20573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b59190611930565b6001600160a01b038416610a915760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610ae75760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b6000610afd610af686866108bc565b848461109e565b9050336001600160a01b0316836001600160a01b0316866001600160a01b03167f13d4d6afcb6d196f753a522f275673066719bb13944bd021efd1fca4286df20d878686604051610b6a9392919092835290151560208301526001600160c01b0316604082015260600190565b60405180910390a45050505050565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae8561084f565b6001600160a01b038416610c1b5760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610c715760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b610cbd610c7e85856108bc565b60009081526001602090815260408083206001600160a01b03871684529091529020805467ffffffffffffffff191667ffffffffffffffff8416179055565b6040805184815267ffffffffffffffff8316602082015233916001600160a01b0385811692908816917f375ee45428e158031095010484fd6451af89c501c79d75e390da4e91eb480ce191015b60405180910390a450505050565b6000610568610d60836040516bffffffffffffffffffffffff19606083901b166020820152600090603401604051602081830303815290604052805190602001209050919050565b7f00000000000000000000000000000000000000000000000000000000000000005b60408051602081018490529081018290526000906060016108e6565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae8561056e565b6001600160a01b038416610e405760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610e965760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b610eaa610ea385856108bc565b83836112a2565b6040805184815267ffffffffffffffff8316602082015233916001600160a01b0385811692908816917ff9b174be67f83278d4516865d1b9ba4576b73e523ea0c2f124ea29152bb1b6769101610d0a565b6001600160a01b038416610f485760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610f9e5760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b6001600160a01b038116610ff45760405162461bcd60e51b815260206004820152601360248201527f5365747465722061646472657373207a65726f000000000000000000000000006044820152606401610452565b60008061100b61100487876108bc565b8585611321565b91509150811561107157604080518681523360208201526001600160c01b0383168183015290516001600160a01b038581169287821692918a16917fdca622020d204c36e9588e7be4184758283d992606ab73318776824b44e2859d9181900360600190a45b505050505050565b60606108b583836040518060600160405280602781526020016119986027913961140f565b60008381526001602090815260408083206001600160a01b0386168452909152902054600160401b90046001600160c01b0316818015611109575060008481526002602090815260408083206001600160a01b0387168452825280832033845290915290205460ff16155b156111975760008481526002602090815260408083206001600160a01b038716845282528083203384529091529020805460ff191660011790558061114d8161194d565b60008681526001602090815260408083206001600160a01b03891684529091529020805467ffffffffffffffff16600160401b6001600160c01b0384160217905591506108b59050565b811580156111cf575060008481526002602090815260408083206001600160a01b0387168452825280832033845290915290205460ff165b156108b55760008481526002602090815260408083206001600160a01b038716845282528083203384529091529020805460ff191690558061121081611974565b60008681526001602090815260408083206001600160a01b0389168452909152902080546001600160c01b038316600160401b0267ffffffffffffffff9091161790559150509392505050565b60009283526001602090815260408085206001600160a01b039490941685529290529120805467ffffffffffffffff191667ffffffffffffffff909216919091179055565b60008381526001602090815260408083206001600160a01b038616845290915290205467ffffffffffffffff9081169082161161125d5760405162461bcd60e51b815260206004820152601a60248201527f446f6573206e6f7420657874656e642065787069726174696f6e0000000000006044820152606401610452565b60008381526001602090815260408083206001600160a01b0386811680865291845282852054888652600285528386209286529184528285209086168552909252822054600160401b9091046001600160c01b03169060ff16156114075760008581526002602090815260408083206001600160a01b03808916855290835281842090871684529091529020805460ff19169055806113bf81611974565b60008781526001602081815260408084206001600160a01b038b168552909152909120805467ffffffffffffffff16600160401b6001600160c01b0385160217905593509150505b935093915050565b6060833b6114855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610452565b600080856001600160a01b0316856040516114a09190611869565b600060405180830381855af49150503d80600081146114db576040519150601f19603f3d011682016040523d82523d6000602084013e6114e0565b606091505b50915091506103f6828286606083156114fa5750816108b5565b82511561150a5782518084602001fd5b8160405162461bcd60e51b815260040161045291906116ed565b80356001600160a01b038116811461153b57600080fd5b919050565b6000806000806080858703121561155657600080fd5b61155f85611524565b93506020850135925061157460408601611524565b915061158260608601611524565b905092959194509250565b600080600080600060a086880312156115a557600080fd5b853594506115b560208701611524565b9350604086013592506115ca60608701611524565b91506115d860808701611524565b90509295509295909350565b80151581146115f257600080fd5b50565b6000806000806080858703121561160b57600080fd5b61161485611524565b93506020850135925061162960408601611524565b91506060850135611639816115e4565b939692955090935050565b6000806000806080858703121561165a57600080fd5b61166385611524565b93506020850135925061167860408601611524565b9150606085013567ffffffffffffffff8116811461163957600080fd5b60005b838110156116b0578181015183820152602001611698565b838111156104675750506000910152565b600081518084526116d9816020860160208601611695565b601f01601f19169290920160200192915050565b6020815260006108b560208301846116c1565b60006020828403121561171257600080fd5b6108b582611524565b60008060006060848603121561173057600080fd5b61173984611524565b92506020840135915061174e60408501611524565b90509250925092565b6000806020838503121561176a57600080fd5b823567ffffffffffffffff8082111561178257600080fd5b818501915085601f83011261179657600080fd5b8135818111156117a557600080fd5b8660208260051b85010111156117ba57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561182157603f1988860301845261180f8583516116c1565b945092850192908501906001016117f3565b5092979650505050505050565b600181811c9082168061184257607f821691505b6020821081141561186357634e487b7160e01b600052602260045260246000fd5b50919050565b6000825161187b818460208701611695565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126118c857600080fd5b83018035915067ffffffffffffffff8211156118e357600080fd5b6020019150368190038213156118f857600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415611929576119296118ff565b5060010190565b60006020828403121561194257600080fd5b81516108b5816115e4565b60006001600160c01b038083168181141561196a5761196a6118ff565b6001019392505050565b60006001600160c01b0382168061198d5761198d6118ff565b600019019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122054c83dd126c12b6928fd970d1f434b676ba73e23c3efdfdac1ccc90a37703ce164736f6c63430008090033", + "devdoc": { + "kind": "dev", + "methods": { + "airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(address,bytes32,address,address)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requester": "Requester address", + "setter": "Address of the account that has potentially whitelisted `requester` for the `airnode`–`endpointId` pair indefinitely" + }, + "returns": { + "indefiniteWhitelistStatus": "If `setter` has indefinitely whitelisted `requester` for the `airnode`–`endpointId` pair" + } + }, + "airnodeToEndpointIdToRequesterToWhitelistStatus(address,bytes32,address)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requester": "Requester address" + }, + "returns": { + "expirationTimestamp": "Timestamp at which the temporary whitelist will expire", + "indefiniteWhitelistCount": "Number of times `requester` was whitelisted indefinitely for the `airnode`–`endpointId` pair" + } + }, + "constructor": { + "params": { + "_accessControlRegistry": "AccessControlRegistry contract address", + "_adminRoleDescription": "Admin role description" + } + }, + "deriveAdminRole(address)": { + "params": { + "airnode": "Airnode address" + }, + "returns": { + "adminRole": "Admin role" + } + }, + "deriveIndefiniteWhitelisterRole(address)": { + "params": { + "airnode": "Airnode address" + }, + "returns": { + "indefiniteWhitelisterRole": "Indefinite whitelister role" + } + }, + "deriveWhitelistExpirationExtenderRole(address)": { + "params": { + "airnode": "Airnode address" + }, + "returns": { + "whitelistExpirationExtenderRole": "Whitelist expiration extender role" + } + }, + "deriveWhitelistExpirationSetterRole(address)": { + "params": { + "airnode": "Airnode address" + }, + "returns": { + "whitelistExpirationSetterRole": "Whitelist expiration setter role" + } + }, + "extendWhitelistExpiration(address,bytes32,address,uint64)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "expirationTimestamp": "Timestamp at which the temporary whitelist will expire", + "requester": "Requester address" + } + }, + "isAuthorized(address,bytes32,address)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requester": "Requester address" + }, + "returns": { + "_0": "Authorization status of the request" + } + }, + "isAuthorizedV0(bytes32,address,bytes32,address,address)": { + "details": "This method has redundant arguments because V0 authorizer contracts have to have the same interface and potential authorizer contracts may require to access the arguments that are redundant here", + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requestId": "Request ID", + "requester": "Requester address", + "sponsor": "Sponsor address" + }, + "returns": { + "_0": "Authorization status of the request" + } + }, + "multicall(bytes[])": { + "details": "Receives and executes a batch of function calls on this contract." + }, + "revokeIndefiniteWhitelistStatus(address,bytes32,address,address)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requester": "Requester address", + "setter": "Setter of the indefinite whitelist status" + } + }, + "setIndefiniteWhitelistStatus(address,bytes32,address,bool)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requester": "Requester address", + "status": "Indefinite whitelist status" + } + }, + "setWhitelistExpiration(address,bytes32,address,uint64)": { + "details": "Unlike `extendWhitelistExpiration()`, this can hasten expiration", + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "expirationTimestamp": "Timestamp at which the temporary whitelist will expire", + "requester": "Requester address" + } + } + }, + "title": "Authorizer contract that Airnode operators can use to temporarily or indefinitely whitelist requesters for Airnode–endpoint pairs", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "INDEFINITE_WHITELISTER_ROLE_DESCRIPTION()": { + "notice": "Indefinite whitelister role description" + }, + "WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION()": { + "notice": "Whitelist expiration extender role description" + }, + "WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION()": { + "notice": "Whitelist expiration setter role description" + }, + "accessControlRegistry()": { + "notice": "AccessControlRegistry contract address" + }, + "adminRoleDescription()": { + "notice": "Admin role description" + }, + "airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(address,bytes32,address,address)": { + "notice": "Returns if an account has indefinitely whitelisted `requester` for the `airnode`–`endpointId` pair" + }, + "airnodeToEndpointIdToRequesterToWhitelistStatus(address,bytes32,address)": { + "notice": "Returns the whitelist status of `requester` for the `airnode`–`endpointId` pair" + }, + "deriveAdminRole(address)": { + "notice": "Derives the admin role for the Airnode" + }, + "deriveIndefiniteWhitelisterRole(address)": { + "notice": "Derives the indefinite whitelister role for the Airnode" + }, + "deriveWhitelistExpirationExtenderRole(address)": { + "notice": "Derives the whitelist expiration extender role for the Airnode" + }, + "deriveWhitelistExpirationSetterRole(address)": { + "notice": "Derives the whitelist expiration setter role for the Airnode" + }, + "extendWhitelistExpiration(address,bytes32,address,uint64)": { + "notice": "Extends the expiration of the temporary whitelist of `requester` for the `airnode`–`endpointId` pair if the sender has the whitelist expiration extender role" + }, + "isAuthorized(address,bytes32,address)": { + "notice": "Verifies the authorization status of a request" + }, + "isAuthorizedV0(bytes32,address,bytes32,address,address)": { + "notice": "Verifies the authorization status of a request" + }, + "revokeIndefiniteWhitelistStatus(address,bytes32,address,address)": { + "notice": "Revokes the indefinite whitelist status granted by a specific account that no longer has the indefinite whitelister role" + }, + "setIndefiniteWhitelistStatus(address,bytes32,address,bool)": { + "notice": "Sets the indefinite whitelist status of `requester` for the `airnode`–`endpointId` pair if the sender has the indefinite whitelister role" + }, + "setWhitelistExpiration(address,bytes32,address,uint64)": { + "notice": "Sets the expiration of the temporary whitelist of `requester` for the `airnode`–`endpointId` pair if the sender has the whitelist expiration setter role" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 1697, + "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", + "label": "adminRoleDescription", + "offset": 0, + "slot": "0", + "type": "t_string_storage" + }, + { + "astId": 5218, + "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", + "label": "serviceIdToUserToWhitelistStatus", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_struct(WhitelistStatus)5211_storage))" + }, + { + "astId": 5226, + "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", + "label": "serviceIdToUserToSetterToIndefiniteWhitelistStatus", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_mapping(t_address,t_bool)))" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_mapping(t_address,t_bool))": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => mapping(address => bool))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_bool)" + }, + "t_mapping(t_address,t_struct(WhitelistStatus)5211_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct Whitelist.WhitelistStatus)", + "numberOfBytes": "32", + "value": "t_struct(WhitelistStatus)5211_storage" + }, + "t_mapping(t_bytes32,t_mapping(t_address,t_mapping(t_address,t_bool)))": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => mapping(address => mapping(address => bool)))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_mapping(t_address,t_bool))" + }, + "t_mapping(t_bytes32,t_mapping(t_address,t_struct(WhitelistStatus)5211_storage))": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => mapping(address => struct Whitelist.WhitelistStatus))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_struct(WhitelistStatus)5211_storage)" + }, + "t_string_storage": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(WhitelistStatus)5211_storage": { + "encoding": "inplace", + "label": "struct Whitelist.WhitelistStatus", + "members": [ + { + "astId": 5208, + "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", + "label": "expirationTimestamp", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 5210, + "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", + "label": "indefiniteWhitelistCount", + "offset": 8, + "slot": "0", + "type": "t_uint192" + } + ], + "numberOfBytes": "32" + }, + "t_uint192": { + "encoding": "inplace", + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint64": { + "encoding": "inplace", + "label": "uint64", + "numberOfBytes": "8" + } + } + } +} diff --git a/packages/airnode-protocol/deployments/lightlink-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json new file mode 100644 index 0000000000..d38c4a14fa --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json @@ -0,0 +1,189 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../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 * ```\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 * ```\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.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => 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 a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role, _msgSender());\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 override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(uint160(account), 20),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\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 override 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 function grantRole(bytes32 role, address account) public virtual override 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 function revokeRole(bytes32 role, address account) public virtual override 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 `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\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 Grants `role` to `account`.\n *\n * Internal function without access restriction.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\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 * _Available since v3.1._\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 `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize, which returns 0 for contracts in\n // construction, since the code is only stored at the end of the\n // constructor execution.\n\n uint256 size;\n assembly {\n size := extcodesize(account)\n }\n return size > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\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" + }, + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s;\n uint8 v;\n assembly {\n s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\n v := add(shr(255, vs), 27)\n }\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./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 *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override 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 v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\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" + }, + "@openzeppelin/contracts/utils/Multicall.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Multicall.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./Address.sol\";\n\n/**\n * @dev Provides a function to batch together multiple calls in a single external call.\n *\n * _Available since v4.1._\n */\nabstract contract Multicall {\n /**\n * @dev Receives and executes a batch of function calls on this contract.\n */\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n results[i] = Address.functionDelegateCall(address(this), data[i]);\n }\n return results;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "contracts/access-control-registry/AccessControlRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"@openzeppelin/contracts/utils/Multicall.sol\";\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"./RoleDeriver.sol\";\nimport \"./interfaces/IAccessControlRegistry.sol\";\n\n/// @title Contract that allows users to manage independent, tree-shaped access\n/// control tables\n/// @notice Multiple contracts can refer to this contract to check if their\n/// users have granted accounts specific roles. Therefore, it aims to keep all\n/// access control roles of its users in this single contract.\n/// @dev Each user is called a \"manager\", and is the only member of their root\n/// role. Starting from this root role, they can create an arbitrary tree of\n/// roles and grant these to accounts. Each role has a description, and roles\n/// adminned by the same role cannot have the same description.\ncontract AccessControlRegistry is\n Multicall,\n AccessControl,\n RoleDeriver,\n IAccessControlRegistry\n{\n /// @notice Initializes the manager by initializing its root role and\n /// granting it to them\n /// @dev Anyone can initialize a manager. An uninitialized manager\n /// attempting to initialize a role will be initialized automatically.\n /// Once a manager is initialized, subsequent initializations have no\n /// effect.\n /// @param manager Manager address to be initialized\n function initializeManager(address manager) public override {\n require(manager != address(0), \"Manager address zero\");\n bytes32 rootRole = deriveRootRole(manager);\n if (!hasRole(rootRole, manager)) {\n _grantRole(rootRole, manager);\n emit InitializedManager(rootRole, manager);\n }\n }\n\n /// @notice Called by the account to renounce the role\n /// @dev Overriden to disallow managers to renounce their root roles.\n /// `role` and `account` are not validated because\n /// `AccessControl.renounceRole` will revert if either of them is zero.\n /// @param role Role to be renounced\n /// @param account Account to renounce the role\n function renounceRole(bytes32 role, address account)\n public\n override(AccessControl, IAccessControl)\n {\n require(\n role != deriveRootRole(account),\n \"role is root role of account\"\n );\n AccessControl.renounceRole(role, account);\n }\n\n /// @notice Initializes a role by setting its admin role and grants it to\n /// the sender\n /// @dev If the sender should not have the initialized role, they should\n /// explicitly renounce it after initializing it.\n /// Once a role is initialized, subsequent initializations have no effect\n /// other than granting the role to the sender.\n /// The sender must be a member of `adminRole`. `adminRole` value is not\n /// validated because the sender cannot have the `bytes32(0)` role.\n /// If the sender is an uninitialized manager that is initializing a role\n /// directly under their root role, manager initialization will happen\n /// automatically, which will grant the sender `adminRole` and allow them\n /// to initialize the role.\n /// @param adminRole Admin role to be assigned to the initialized role\n /// @param description Human-readable description of the initialized role\n /// @return role Initialized role\n function initializeRoleAndGrantToSender(\n bytes32 adminRole,\n string calldata description\n ) external override returns (bytes32 role) {\n require(bytes(description).length > 0, \"Role description empty\");\n role = deriveRole(adminRole, description);\n // AccessControl roles have `DEFAULT_ADMIN_ROLE` (i.e., `bytes32(0)`)\n // as their `adminRole` by default. No account in AccessControlRegistry\n // can possibly have that role, which means all initialized roles will\n // have non-default admin roles, and vice versa.\n if (getRoleAdmin(role) == DEFAULT_ADMIN_ROLE) {\n if (adminRole == deriveRootRole(_msgSender())) {\n initializeManager(_msgSender());\n }\n _setRoleAdmin(role, adminRole);\n emit InitializedRole(role, adminRole, description, _msgSender());\n }\n grantRole(role, _msgSender());\n }\n\n /// @notice Derives the root role of the manager\n /// @param manager Manager address\n /// @return rootRole Root role\n function deriveRootRole(address manager)\n public\n pure\n override\n returns (bytes32 rootRole)\n {\n rootRole = _deriveRootRole(manager);\n }\n\n /// @notice Derives the role using its admin role and description\n /// @dev This implies that roles adminned by the same role cannot have the\n /// same description\n /// @param adminRole Admin role\n /// @param description Human-readable description of the role\n /// @return role Role\n function deriveRole(bytes32 adminRole, string calldata description)\n public\n pure\n override\n returns (bytes32 role)\n {\n role = _deriveRole(adminRole, description);\n }\n}\n" + }, + "contracts/access-control-registry/AccessControlRegistryAdminned.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Multicall.sol\";\nimport \"./RoleDeriver.sol\";\nimport \"./AccessControlRegistryUser.sol\";\nimport \"./interfaces/IAccessControlRegistryAdminned.sol\";\n\n/// @title Contract to be inherited by contracts whose adminship functionality\n/// will be implemented using AccessControlRegistry\ncontract AccessControlRegistryAdminned is\n Multicall,\n RoleDeriver,\n AccessControlRegistryUser,\n IAccessControlRegistryAdminned\n{\n /// @notice Admin role description\n string public override adminRoleDescription;\n\n bytes32 internal immutable adminRoleDescriptionHash;\n\n /// @dev Contracts deployed with the same admin role descriptions will have\n /// the same roles, meaning that granting an account a role will authorize\n /// it in multiple contracts. Unless you want your deployed contract to\n /// share the role configuration of another contract, use a unique admin\n /// role description.\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription\n ) AccessControlRegistryUser(_accessControlRegistry) {\n require(\n bytes(_adminRoleDescription).length > 0,\n \"Admin role description empty\"\n );\n adminRoleDescription = _adminRoleDescription;\n adminRoleDescriptionHash = keccak256(\n abi.encodePacked(_adminRoleDescription)\n );\n }\n\n /// @notice Derives the admin role for the specific manager address\n /// @param manager Manager address\n /// @return adminRole Admin role\n function _deriveAdminRole(address manager)\n internal\n view\n returns (bytes32 adminRole)\n {\n adminRole = _deriveRole(\n _deriveRootRole(manager),\n adminRoleDescriptionHash\n );\n }\n}\n" + }, + "contracts/access-control-registry/AccessControlRegistryAdminnedWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./AccessControlRegistryAdminned.sol\";\nimport \"./interfaces/IAccessControlRegistryAdminnedWithManager.sol\";\n\n/// @title Contract to be inherited by contracts with manager whose adminship\n/// functionality will be implemented using AccessControlRegistry\n/// @notice The manager address here is expected to belong to an\n/// AccessControlRegistry user that is a multisig/DAO\ncontract AccessControlRegistryAdminnedWithManager is\n AccessControlRegistryAdminned,\n IAccessControlRegistryAdminnedWithManager\n{\n /// @notice Address of the manager that manages the related\n /// AccessControlRegistry roles\n /// @dev The mutability of the manager role can be implemented by\n /// designating an OwnableCallForwarder contract as the manager. The\n /// ownership of this contract can then be transferred, effectively\n /// transferring managership.\n address public immutable override manager;\n\n /// @notice Admin role\n /// @dev Since `manager` is immutable, so is `adminRole`\n bytes32 public immutable override adminRole;\n\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n /// @param _manager Manager address\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription,\n address _manager\n )\n AccessControlRegistryAdminned(\n _accessControlRegistry,\n _adminRoleDescription\n )\n {\n require(_manager != address(0), \"Manager address zero\");\n manager = _manager;\n adminRole = _deriveAdminRole(_manager);\n }\n}\n" + }, + "contracts/access-control-registry/AccessControlRegistryUser.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interfaces/IAccessControlRegistry.sol\";\nimport \"./interfaces/IAccessControlRegistryUser.sol\";\n\n/// @title Contract to be inherited by contracts that will interact with\n/// AccessControlRegistry\ncontract AccessControlRegistryUser is IAccessControlRegistryUser {\n /// @notice AccessControlRegistry contract address\n address public immutable override accessControlRegistry;\n\n /// @param _accessControlRegistry AccessControlRegistry contract address\n constructor(address _accessControlRegistry) {\n require(_accessControlRegistry != address(0), \"ACR address zero\");\n accessControlRegistry = _accessControlRegistry;\n }\n}\n" + }, + "contracts/access-control-registry/interfaces/IAccessControlRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\ninterface IAccessControlRegistry is IAccessControl {\n event InitializedManager(bytes32 indexed rootRole, address indexed manager);\n\n event InitializedRole(\n bytes32 indexed role,\n bytes32 indexed adminRole,\n string description,\n address sender\n );\n\n function initializeManager(address manager) external;\n\n function initializeRoleAndGrantToSender(\n bytes32 adminRole,\n string calldata description\n ) external returns (bytes32 role);\n\n function deriveRootRole(address manager)\n external\n pure\n returns (bytes32 rootRole);\n\n function deriveRole(bytes32 adminRole, string calldata description)\n external\n pure\n returns (bytes32 role);\n}\n" + }, + "contracts/access-control-registry/interfaces/IAccessControlRegistryAdminned.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlRegistryUser.sol\";\n\ninterface IAccessControlRegistryAdminned is IAccessControlRegistryUser {\n function adminRoleDescription() external view returns (string memory);\n}\n" + }, + "contracts/access-control-registry/interfaces/IAccessControlRegistryAdminnedWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlRegistryAdminned.sol\";\n\ninterface IAccessControlRegistryAdminnedWithManager is\n IAccessControlRegistryAdminned\n{\n function manager() external view returns (address);\n\n function adminRole() external view returns (bytes32);\n}\n" + }, + "contracts/access-control-registry/interfaces/IAccessControlRegistryUser.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IAccessControlRegistryUser {\n function accessControlRegistry() external view returns (address);\n}\n" + }, + "contracts/access-control-registry/RoleDeriver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Contract to be inherited by contracts that will derive\n/// AccessControlRegistry roles\n/// @notice If a contract interfaces with AccessControlRegistry and needs to\n/// derive roles, it should inherit this contract instead of re-implementing\n/// the logic\ncontract RoleDeriver {\n /// @notice Derives the root role of the manager\n /// @param manager Manager address\n /// @return rootRole Root role\n function _deriveRootRole(address manager)\n internal\n pure\n returns (bytes32 rootRole)\n {\n rootRole = keccak256(abi.encodePacked(manager));\n }\n\n /// @notice Derives the role using its admin role and description\n /// @dev This implies that roles adminned by the same role cannot have the\n /// same description\n /// @param adminRole Admin role\n /// @param description Human-readable description of the role\n /// @return role Role\n function _deriveRole(bytes32 adminRole, string memory description)\n internal\n pure\n returns (bytes32 role)\n {\n role = _deriveRole(adminRole, keccak256(abi.encodePacked(description)));\n }\n\n /// @notice Derives the role using its admin role and description hash\n /// @dev This implies that roles adminned by the same role cannot have the\n /// same description\n /// @param adminRole Admin role\n /// @param descriptionHash Hash of the human-readable description of the\n /// role\n /// @return role Role\n function _deriveRole(bytes32 adminRole, bytes32 descriptionHash)\n internal\n pure\n returns (bytes32 role)\n {\n role = keccak256(abi.encodePacked(adminRole, descriptionHash));\n }\n}\n" + }, + "contracts/authorizers/interfaces/IAuthorizerV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IAuthorizerV0 {\n function isAuthorizedV0(\n bytes32 requestId,\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address requester\n ) external view returns (bool);\n}\n" + }, + "contracts/authorizers/interfaces/IRequesterAuthorizer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IAuthorizerV0.sol\";\n\ninterface IRequesterAuthorizer is IAuthorizerV0 {\n event ExtendedWhitelistExpiration(\n address indexed airnode,\n bytes32 endpointId,\n address indexed requester,\n address indexed sender,\n uint256 expiration\n );\n\n event SetWhitelistExpiration(\n address indexed airnode,\n bytes32 endpointId,\n address indexed requester,\n address indexed sender,\n uint256 expiration\n );\n\n event SetIndefiniteWhitelistStatus(\n address indexed airnode,\n bytes32 endpointId,\n address indexed requester,\n address indexed sender,\n bool status,\n uint192 indefiniteWhitelistCount\n );\n\n event RevokedIndefiniteWhitelistStatus(\n address indexed airnode,\n bytes32 endpointId,\n address indexed requester,\n address indexed setter,\n address sender,\n uint192 indefiniteWhitelistCount\n );\n\n function extendWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external;\n\n function setWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external;\n\n function setIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n bool status\n ) external;\n\n function revokeIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) external;\n\n function airnodeToEndpointIdToRequesterToWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester\n )\n external\n view\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount);\n\n function airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) external view returns (bool indefiniteWhitelistStatus);\n\n function isAuthorized(\n address airnode,\n bytes32 endpointId,\n address requester\n ) external view returns (bool);\n}\n" + }, + "contracts/authorizers/interfaces/IRequesterAuthorizerWithAirnode.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../whitelist/interfaces/IWhitelistRolesWithAirnode.sol\";\nimport \"./IRequesterAuthorizer.sol\";\n\ninterface IRequesterAuthorizerWithAirnode is\n IWhitelistRolesWithAirnode,\n IRequesterAuthorizer\n{}\n" + }, + "contracts/authorizers/interfaces/IRequesterAuthorizerWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../whitelist/interfaces/IWhitelistRolesWithManager.sol\";\nimport \"./IRequesterAuthorizer.sol\";\n\ninterface IRequesterAuthorizerWithManager is\n IWhitelistRolesWithManager,\n IRequesterAuthorizer\n{}\n" + }, + "contracts/authorizers/mock/MockAuthorizerAlwaysFalseV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../interfaces/IAuthorizerV0.sol\";\n\n/// @title A mock authorizer that always returns false\ncontract MockAuthorizerAlwaysFalseV0 is IAuthorizerV0 {\n function isAuthorizedV0(\n bytes32 requestId, // solhint-disable-line\n address airnode, // solhint-disable-line\n bytes32 endpointId, // solhint-disable-line\n address sponsor, // solhint-disable-line\n address requester // solhint-disable-line\n ) external view virtual override returns (bool status) {\n status = false;\n }\n}\n" + }, + "contracts/authorizers/mock/MockAuthorizerAlwaysTrueV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../interfaces/IAuthorizerV0.sol\";\n\n/// @title A mock authorizer that always returns true\ncontract MockAuthorizerAlwaysTrueV0 is IAuthorizerV0 {\n function isAuthorizedV0(\n bytes32 requestId, // solhint-disable-line\n address airnode, // solhint-disable-line\n bytes32 endpointId, // solhint-disable-line\n address sponsor, // solhint-disable-line\n address requester // solhint-disable-line\n ) external view virtual override returns (bool status) {\n status = true;\n }\n}\n" + }, + "contracts/authorizers/RequesterAuthorizer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../whitelist/Whitelist.sol\";\nimport \"./interfaces/IRequesterAuthorizer.sol\";\n\n/// @title Abstract contract to be inherited by Authorizer contracts that\n/// temporarily or permanently whitelist requesters for Airnode–endpoint pairs\nabstract contract RequesterAuthorizer is Whitelist, IRequesterAuthorizer {\n /// @notice Extends the expiration of the temporary whitelist of\n /// `requester` for the `airnode`–`endpointId` pair and emits an event\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function _extendWhitelistExpirationAndEmit(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) internal {\n require(airnode != address(0), \"Airnode address zero\");\n require(requester != address(0), \"Requester address zero\");\n _extendWhitelistExpiration(\n deriveServiceId(airnode, endpointId),\n requester,\n expirationTimestamp\n );\n emit ExtendedWhitelistExpiration(\n airnode,\n endpointId,\n requester,\n msg.sender,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the expiration of the temporary whitelist of `requester`\n /// for the `airnode`–`endpointId` pair and emits an event\n /// @dev Unlike `_extendWhitelistExpiration()`, this can hasten expiration\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function _setWhitelistExpirationAndEmit(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) internal {\n require(airnode != address(0), \"Airnode address zero\");\n require(requester != address(0), \"Requester address zero\");\n _setWhitelistExpiration(\n deriveServiceId(airnode, endpointId),\n requester,\n expirationTimestamp\n );\n emit SetWhitelistExpiration(\n airnode,\n endpointId,\n requester,\n msg.sender,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the indefinite whitelist status of `requester` for the\n /// `airnode`–`endpointId` pair and emits an event\n /// @dev Emits the event even if it does not change the state.\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param requester Requester address\n /// @param status Indefinite whitelist status\n function _setIndefiniteWhitelistStatusAndEmit(\n address airnode,\n bytes32 endpointId,\n address requester,\n bool status\n ) internal {\n require(airnode != address(0), \"Airnode address zero\");\n require(requester != address(0), \"Requester address zero\");\n uint192 indefiniteWhitelistCount = _setIndefiniteWhitelistStatus(\n deriveServiceId(airnode, endpointId),\n requester,\n status\n );\n emit SetIndefiniteWhitelistStatus(\n airnode,\n endpointId,\n requester,\n msg.sender,\n status,\n indefiniteWhitelistCount\n );\n }\n\n /// @notice Revokes the indefinite whitelist status granted to `requester`\n /// for the `airnode`–`endpointId` pair by a specific account and emits an\n /// event\n /// @dev Only emits the event if it changes the state\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param requester Requester address\n /// @param setter Setter of the indefinite whitelist status\n function _revokeIndefiniteWhitelistStatusAndEmit(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) internal {\n require(airnode != address(0), \"Airnode address zero\");\n require(requester != address(0), \"Requester address zero\");\n require(setter != address(0), \"Setter address zero\");\n (\n bool revoked,\n uint192 indefiniteWhitelistCount\n ) = _revokeIndefiniteWhitelistStatus(\n deriveServiceId(airnode, endpointId),\n requester,\n setter\n );\n if (revoked) {\n emit RevokedIndefiniteWhitelistStatus(\n airnode,\n endpointId,\n requester,\n setter,\n msg.sender,\n indefiniteWhitelistCount\n );\n }\n }\n\n /// @notice Verifies the authorization status of a request\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @return Authorization status of the request\n function isAuthorized(\n address airnode,\n bytes32 endpointId,\n address requester\n ) external view override returns (bool) {\n return\n userIsWhitelisted(deriveServiceId(airnode, endpointId), requester);\n }\n\n /// @notice Verifies the authorization status of a request\n /// @dev This method has redundant arguments because V0 authorizer\n /// contracts have to have the same interface and potential authorizer\n /// contracts may require to access the arguments that are redundant here\n /// @param requestId Request ID\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param requester Requester address\n /// @return Authorization status of the request\n function isAuthorizedV0(\n bytes32 requestId, // solhint-disable-line no-unused-vars\n address airnode,\n bytes32 endpointId,\n address sponsor, // solhint-disable-line no-unused-vars\n address requester\n ) external view override returns (bool) {\n return\n userIsWhitelisted(deriveServiceId(airnode, endpointId), requester);\n }\n\n /// @notice Returns the whitelist status of `requester` for the\n /// `airnode`–`endpointId` pair\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @return expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n /// @return indefiniteWhitelistCount Number of times `requester` was\n /// whitelisted indefinitely for the `airnode`–`endpointId` pair\n function airnodeToEndpointIdToRequesterToWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester\n )\n external\n view\n override\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount)\n {\n WhitelistStatus\n storage whitelistStatus = serviceIdToUserToWhitelistStatus[\n deriveServiceId(airnode, endpointId)\n ][requester];\n expirationTimestamp = whitelistStatus.expirationTimestamp;\n indefiniteWhitelistCount = whitelistStatus.indefiniteWhitelistCount;\n }\n\n /// @notice Returns if an account has indefinitely whitelisted `requester`\n /// for the `airnode`–`endpointId` pair\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param setter Address of the account that has potentially whitelisted\n /// `requester` for the `airnode`–`endpointId` pair indefinitely\n /// @return indefiniteWhitelistStatus If `setter` has indefinitely\n /// whitelisted `requester` for the `airnode`–`endpointId` pair\n function airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) external view override returns (bool indefiniteWhitelistStatus) {\n indefiniteWhitelistStatus = serviceIdToUserToSetterToIndefiniteWhitelistStatus[\n deriveServiceId(airnode, endpointId)\n ][requester][setter];\n }\n\n /// @notice Called privately to derive a service ID out of the Airnode\n /// address and the endpoint ID\n /// @dev This is done to re-use the more general Whitelist contract for\n /// the specific case of Airnode–endpoint pairs\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @return serviceId Service ID\n function deriveServiceId(address airnode, bytes32 endpointId)\n private\n pure\n returns (bytes32 serviceId)\n {\n serviceId = keccak256(abi.encodePacked(airnode, endpointId));\n }\n}\n" + }, + "contracts/authorizers/RequesterAuthorizerWithAirnode.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../whitelist/WhitelistRolesWithAirnode.sol\";\nimport \"./RequesterAuthorizer.sol\";\nimport \"./interfaces/IRequesterAuthorizerWithAirnode.sol\";\n\n/// @title Authorizer contract that Airnode operators can use to temporarily or\n/// indefinitely whitelist requesters for Airnode–endpoint pairs\ncontract RequesterAuthorizerWithAirnode is\n WhitelistRolesWithAirnode,\n RequesterAuthorizer,\n IRequesterAuthorizerWithAirnode\n{\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription\n )\n WhitelistRolesWithAirnode(_accessControlRegistry, _adminRoleDescription)\n {}\n\n /// @notice Extends the expiration of the temporary whitelist of\n /// `requester` for the `airnode`–`endpointId` pair if the sender has the\n /// whitelist expiration extender role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function extendWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationExtenderRoleOrIsAirnode(airnode, msg.sender),\n \"Cannot extend expiration\"\n );\n _extendWhitelistExpirationAndEmit(\n airnode,\n endpointId,\n requester,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the expiration of the temporary whitelist of `requester`\n /// for the `airnode`–`endpointId` pair if the sender has the whitelist\n /// expiration setter role\n /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function setWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationSetterRoleOrIsAirnode(airnode, msg.sender),\n \"Cannot set expiration\"\n );\n _setWhitelistExpirationAndEmit(\n airnode,\n endpointId,\n requester,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the indefinite whitelist status of `requester` for the\n /// `airnode`–`endpointId` pair if the sender has the indefinite\n /// whitelister role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param status Indefinite whitelist status\n function setIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n bool status\n ) external override {\n require(\n hasIndefiniteWhitelisterRoleOrIsAirnode(airnode, msg.sender),\n \"Cannot set indefinite status\"\n );\n _setIndefiniteWhitelistStatusAndEmit(\n airnode,\n endpointId,\n requester,\n status\n );\n }\n\n /// @notice Revokes the indefinite whitelist status granted by a specific\n /// account that no longer has the indefinite whitelister role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param setter Setter of the indefinite whitelist status\n function revokeIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) external override {\n require(\n !hasIndefiniteWhitelisterRoleOrIsAirnode(airnode, setter),\n \"setter can set indefinite status\"\n );\n _revokeIndefiniteWhitelistStatusAndEmit(\n airnode,\n endpointId,\n requester,\n setter\n );\n }\n}\n" + }, + "contracts/authorizers/RequesterAuthorizerWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../whitelist/WhitelistRolesWithManager.sol\";\nimport \"./RequesterAuthorizer.sol\";\nimport \"./interfaces/IRequesterAuthorizerWithManager.sol\";\n\n/// @title Authorizer contract that a manager can use to temporarily or\n/// indefinitely whitelist requesters for Airnode–endpoint pairs\ncontract RequesterAuthorizerWithManager is\n WhitelistRolesWithManager,\n RequesterAuthorizer,\n IRequesterAuthorizerWithManager\n{\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n /// @param _manager Manager address\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription,\n address _manager\n )\n WhitelistRolesWithManager(\n _accessControlRegistry,\n _adminRoleDescription,\n _manager\n )\n {}\n\n /// @notice Extends the expiration of the temporary whitelist of\n /// `requester` for the `airnode`–`endpointId` pair if the sender has the\n /// whitelist expiration extender role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function extendWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationExtenderRoleOrIsManager(msg.sender),\n \"Cannot extend expiration\"\n );\n _extendWhitelistExpirationAndEmit(\n airnode,\n endpointId,\n requester,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the expiration of the temporary whitelist of `requester`\n /// for the `airnode`–`endpointId` pair if the sender has the whitelist\n /// expiration setter role\n /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function setWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationSetterRoleOrIsManager(msg.sender),\n \"Cannot set expiration\"\n );\n _setWhitelistExpirationAndEmit(\n airnode,\n endpointId,\n requester,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the indefinite whitelist status of `requester` for the\n /// `airnode`–`endpointId` pair if the sender has the indefinite\n /// whitelister role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param status Indefinite whitelist status\n function setIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n bool status\n ) external override {\n require(\n hasIndefiniteWhitelisterRoleOrIsManager(msg.sender),\n \"Cannot set indefinite status\"\n );\n _setIndefiniteWhitelistStatusAndEmit(\n airnode,\n endpointId,\n requester,\n status\n );\n }\n\n /// @notice Revokes the indefinite whitelist status granted by a specific\n /// account that no longer has the indefinite whitelister role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param setter Setter of the indefinite whitelist status\n function revokeIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) external override {\n require(\n !hasIndefiniteWhitelisterRoleOrIsManager(setter),\n \"setter can set indefinite status\"\n );\n _revokeIndefiniteWhitelistStatusAndEmit(\n airnode,\n endpointId,\n requester,\n setter\n );\n }\n}\n" + }, + "contracts/rrp/AirnodeRrpV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"./AuthorizationUtilsV0.sol\";\nimport \"./TemplateUtilsV0.sol\";\nimport \"./WithdrawalUtilsV0.sol\";\nimport \"./interfaces/IAirnodeRrpV0.sol\";\n\n/// @title Contract that implements the Airnode request–response protocol (RRP)\ncontract AirnodeRrpV0 is\n AuthorizationUtilsV0,\n TemplateUtilsV0,\n WithdrawalUtilsV0,\n IAirnodeRrpV0\n{\n using ECDSA for bytes32;\n\n /// @notice Called to get the sponsorship status for a sponsor–requester\n /// pair\n mapping(address => mapping(address => bool))\n public\n override sponsorToRequesterToSponsorshipStatus;\n\n /// @notice Called to get the request count of the requester plus one\n /// @dev Can be used to calculate the ID of the next request the requester\n /// will make\n mapping(address => uint256) public override requesterToRequestCountPlusOne;\n\n /// @dev Hash of expected fulfillment parameters are kept to verify that\n /// the fulfillment will be done with the correct parameters. This value is\n /// also used to check if the fulfillment for the particular request is\n /// expected, i.e., if there are recorded fulfillment parameters.\n mapping(bytes32 => bytes32) private requestIdToFulfillmentParameters;\n\n /// @notice Called by the sponsor to set the sponsorship status of a\n /// requester, i.e., allow or disallow a requester to make requests that\n /// will be fulfilled by the sponsor wallet\n /// @dev This is not Airnode-specific, i.e., the sponsor allows the\n /// requester's requests to be fulfilled through its sponsor wallets across\n /// all Airnodes\n /// @param requester Requester address\n /// @param sponsorshipStatus Sponsorship status\n function setSponsorshipStatus(address requester, bool sponsorshipStatus)\n external\n override\n {\n // Initialize the requester request count for consistent request gas\n // cost\n if (requesterToRequestCountPlusOne[requester] == 0) {\n requesterToRequestCountPlusOne[requester] = 1;\n }\n sponsorToRequesterToSponsorshipStatus[msg.sender][\n requester\n ] = sponsorshipStatus;\n emit SetSponsorshipStatus(msg.sender, requester, sponsorshipStatus);\n }\n\n /// @notice Called by the requester to make a request that refers to a\n /// template for the Airnode address, endpoint ID and parameters\n /// @dev `fulfillAddress` is not allowed to be the address of this\n /// contract. This is not actually needed to protect users that use the\n /// protocol as intended, but it is done for good measure.\n /// @param templateId Template ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill the\n /// request\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @param parameters Parameters provided by the requester in addition to\n /// the parameters in the template\n /// @return requestId Request ID\n function makeTemplateRequest(\n bytes32 templateId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external override returns (bytes32 requestId) {\n address airnode = templates[templateId].airnode;\n // If the Airnode address of the template is zero the template does not\n // exist because template creation does not allow zero Airnode address\n require(airnode != address(0), \"Template does not exist\");\n require(fulfillAddress != address(this), \"Fulfill address AirnodeRrp\");\n require(\n sponsorToRequesterToSponsorshipStatus[sponsor][msg.sender],\n \"Requester not sponsored\"\n );\n uint256 requesterRequestCount = requesterToRequestCountPlusOne[\n msg.sender\n ];\n requestId = keccak256(\n abi.encodePacked(\n block.chainid,\n address(this),\n msg.sender,\n requesterRequestCount,\n templateId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n )\n );\n requestIdToFulfillmentParameters[requestId] = keccak256(\n abi.encodePacked(\n airnode,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId\n )\n );\n requesterToRequestCountPlusOne[msg.sender]++;\n emit MadeTemplateRequest(\n airnode,\n requestId,\n requesterRequestCount,\n block.chainid,\n msg.sender,\n templateId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n );\n }\n\n /// @notice Called by the requester to make a full request, which provides\n /// all of its parameters as arguments and does not refer to a template\n /// @dev `fulfillAddress` is not allowed to be the address of this\n /// contract. This is not actually needed to protect users that use the\n /// protocol as intended, but it is done for good measure.\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill\n /// the request\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @param parameters All request parameters\n /// @return requestId Request ID\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external override returns (bytes32 requestId) {\n require(airnode != address(0), \"Airnode address zero\");\n require(fulfillAddress != address(this), \"Fulfill address AirnodeRrp\");\n require(\n sponsorToRequesterToSponsorshipStatus[sponsor][msg.sender],\n \"Requester not sponsored\"\n );\n uint256 requesterRequestCount = requesterToRequestCountPlusOne[\n msg.sender\n ];\n requestId = keccak256(\n abi.encodePacked(\n block.chainid,\n address(this),\n msg.sender,\n requesterRequestCount,\n airnode,\n endpointId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n )\n );\n requestIdToFulfillmentParameters[requestId] = keccak256(\n abi.encodePacked(\n airnode,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId\n )\n );\n requesterToRequestCountPlusOne[msg.sender]++;\n emit MadeFullRequest(\n airnode,\n requestId,\n requesterRequestCount,\n block.chainid,\n msg.sender,\n endpointId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n );\n }\n\n /// @notice Called by Airnode to fulfill the request (template or full)\n /// @dev The data is ABI-encoded as a `bytes` type, with its format\n /// depending on the request specifications.\n /// This will not revert depending on the external call. However, it will\n /// return `false` if the external call reverts or if there is no function\n /// with a matching signature at `fulfillAddress`. On the other hand, it\n /// will return `true` if the external call returns successfully or if\n /// there is no contract deployed at `fulfillAddress`.\n /// If `callSuccess` is `false`, `callData` can be decoded to retrieve the\n /// revert string.\n /// This function emits its event after an untrusted low-level call,\n /// meaning that the order of these events within the transaction should\n /// not be taken seriously, yet the content will be sound.\n /// @param requestId Request ID\n /// @param airnode Airnode address\n /// @param data Fulfillment data\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @return callSuccess If the fulfillment call succeeded\n /// @return callData Data returned by the fulfillment call (if there is\n /// any)\n function fulfill(\n bytes32 requestId,\n address airnode,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata data,\n bytes calldata signature\n ) external override returns (bool callSuccess, bytes memory callData) {\n require(\n keccak256(\n abi.encodePacked(\n airnode,\n msg.sender,\n fulfillAddress,\n fulfillFunctionId\n )\n ) == requestIdToFulfillmentParameters[requestId],\n \"Invalid request fulfillment\"\n );\n require(\n (\n keccak256(abi.encodePacked(requestId, data))\n .toEthSignedMessageHash()\n ).recover(signature) == airnode,\n \"Invalid signature\"\n );\n delete requestIdToFulfillmentParameters[requestId];\n (callSuccess, callData) = fulfillAddress.call( // solhint-disable-line avoid-low-level-calls\n abi.encodeWithSelector(fulfillFunctionId, requestId, data)\n );\n if (callSuccess) {\n emit FulfilledRequest(airnode, requestId, data);\n } else {\n // We do not bubble up the revert string from `callData`\n emit FailedRequest(\n airnode,\n requestId,\n \"Fulfillment failed unexpectedly\"\n );\n }\n }\n\n /// @notice Called by Airnode if the request cannot be fulfilled\n /// @dev Airnode should fall back to this if a request cannot be fulfilled\n /// because static call to `fulfill()` returns `false` for `callSuccess`\n /// @param requestId Request ID\n /// @param airnode Airnode address\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @param errorMessage A message that explains why the request has failed\n function fail(\n bytes32 requestId,\n address airnode,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n string calldata errorMessage\n ) external override {\n require(\n keccak256(\n abi.encodePacked(\n airnode,\n msg.sender,\n fulfillAddress,\n fulfillFunctionId\n )\n ) == requestIdToFulfillmentParameters[requestId],\n \"Invalid request fulfillment\"\n );\n delete requestIdToFulfillmentParameters[requestId];\n emit FailedRequest(airnode, requestId, errorMessage);\n }\n\n /// @notice Called to check if the request with the ID is made but not\n /// fulfilled/failed yet\n /// @dev If a requester has made a request, received a request ID but did\n /// not hear back, it can call this method to check if the Airnode has\n /// called back `fail()` instead.\n /// @param requestId Request ID\n /// @return isAwaitingFulfillment If the request is awaiting fulfillment\n /// (i.e., `true` if `fulfill()` or `fail()` is not called back yet,\n /// `false` otherwise)\n function requestIsAwaitingFulfillment(bytes32 requestId)\n external\n view\n override\n returns (bool isAwaitingFulfillment)\n {\n isAwaitingFulfillment =\n requestIdToFulfillmentParameters[requestId] != bytes32(0);\n }\n}\n" + }, + "contracts/rrp/AirnodeRrpV0DryRun.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\n\n/// @title Contract that complements Airnode request–response protocol (RRP) to\n/// allow Airnode to estimate the gas required to execute a fulfillment\n/// @dev Typically, contracts are built to revert when an external call they\n/// make reverts. In contrast, AirnodeRrpV0 does not revert when the external\n/// call during the fulfillment reverts, and instead fails gracefully by\n/// emitting a `FailedRequest` event. This event signals to the future\n/// invocations of the stateless Airnode to not retry the failed fulfillment.\n/// Although this approach meets the intended purpose, it disables Airnode from\n/// calling `eth_estimateGas` on `fulfill()` to estimate the gas amount that\n/// will be used to execute a fulfillment successfully. Specifically, since\n/// `eth_estimateGas` looks for the lowest gas limit that results in the\n/// transaction not reverting, and AirnodeRrpV0's `fulfill()` does not revert\n/// when its external call reverts (because it runs out of gas),\n/// `eth_estimateGas` will not necessarily return a gas amount that will result\n/// in the fulfillment to be successful even if such an amount exists.\n/// As a solution, Airnode calls `eth_estimateGas` on AirnodeRrpV0DryRun's\n/// `fulfill()` and the external call of the fulfillment, and add these up to\n/// find the gas limit required to execute a successful fulfillment. This\n/// sum is an overestimation of the actual requirement, as it includes an\n/// additional base fee (21,000 gas on Ethereum).\ncontract AirnodeRrpV0DryRun\n{\n using ECDSA for bytes32;\n\n event FulfilledRequest(\n address indexed airnode,\n bytes32 indexed requestId,\n bytes data\n );\n\n /// @dev This mapping is kept as it is in AirnodeRrpV0 to closely simulate\n /// the fulfillment. All of its keys will map to zero values.\n mapping(bytes32 => bytes32) private requestIdToFulfillmentParameters;\n\n /// @notice Used by Airnode to estimate the gas amount needed to fulfill\n /// the request (excluding the external call). Do not call this function,\n /// as it will have no practical effect.\n /// @dev Refer to AirnodeRrpV0's `fulfill()` for more information\n /// @param requestId Request ID\n /// @param airnode Airnode address\n /// @param data Fulfillment data\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @return callSuccess If the fulfillment call succeeded\n /// @return callData Data returned by the fulfillment call (if there is\n /// any)\n function fulfill(\n bytes32 requestId,\n address airnode,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata data,\n bytes calldata signature\n ) external returns (bool callSuccess, bytes memory callData) {\n // The line below is kept the same, except that the condition is\n // reversed to ensure that it never reverts. All\n // `requestIdToFulfillmentParameters` values are zero and virtually no\n // `keccak256()` output will be equal to that.\n require(\n keccak256(\n abi.encodePacked(\n airnode,\n msg.sender,\n fulfillAddress,\n fulfillFunctionId\n )\n ) != requestIdToFulfillmentParameters[requestId],\n \"Dummy revert string\"\n );\n // The line below does not need to be modified\n require(\n (\n keccak256(abi.encodePacked(requestId, data))\n .toEthSignedMessageHash()\n ).recover(signature) == airnode,\n \"Invalid signature\"\n );\n // We cannot call `fulfillAddress` below because (1) we do not want\n // this function to actually fulfill the request (2) the fulfill\n // function will be behind an `onlyAirnodeRrp` modifier and will reject\n // the calls from AirnodeRrpV0DryRun.\n // Instead, we call an address that we know to not contain any\n // bytecode, which will result in the call to not revert or spend extra\n // gas. Since we have already confirmed that `airnode` has signed a\n // hash, it is guaranteed to be an EOA and we can use it as a dummy\n // call target.\n (callSuccess, callData) = airnode.call( // solhint-disable-line avoid-low-level-calls\n abi.encodeWithSelector(fulfillFunctionId, requestId, data)\n );\n // If the external call above does not succeed, the `eth_estimateGas`\n // called on the external call will not be able to return a gas amount.\n // AirnodeRrpV0DryRun's `fulfill()` optimistically estimates the\n // AirnodeRrpV0 overhead of a fulfillment, and expects Airnode to\n // detect if the external call will succeed (by calling\n // `eth_estimateGas` on it) independently. Therefore, we do not need to\n // consider the unhappy path here.\n if (callSuccess) {\n emit FulfilledRequest(airnode, requestId, data);\n }\n }\n}\n" + }, + "contracts/rrp/AuthorizationUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interfaces/IAuthorizationUtilsV0.sol\";\nimport \"../authorizers/interfaces/IAuthorizerV0.sol\";\n\n/// @title Contract that implements authorization checks\ncontract AuthorizationUtilsV0 is IAuthorizationUtilsV0 {\n /// @notice Uses the authorizer contracts of an Airnode to decide if a\n /// request is authorized. Once an Airnode receives a request, it calls\n /// this method to determine if it should respond. Similarly, third parties\n /// can use this method to determine if a particular request would be\n /// authorized.\n /// @dev This method is meant to be called off-chain, statically by the\n /// Airnode to decide if it should respond to a request. The requester can\n /// also call it, yet this function returning true should not be taken as a\n /// guarantee of the subsequent request being fulfilled.\n /// It is enough for only one of the authorizer contracts to return true\n /// for the request to be authorized.\n /// @param authorizers Authorizer contract addresses\n /// @param airnode Airnode address\n /// @param requestId Request ID\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param requester Requester address\n /// @return status Authorization status of the request\n function checkAuthorizationStatus(\n address[] calldata authorizers,\n address airnode,\n bytes32 requestId,\n bytes32 endpointId,\n address sponsor,\n address requester\n ) public view override returns (bool status) {\n for (uint256 ind = 0; ind < authorizers.length; ind++) {\n IAuthorizerV0 authorizer = IAuthorizerV0(authorizers[ind]);\n if (\n authorizer.isAuthorizedV0(\n requestId,\n airnode,\n endpointId,\n sponsor,\n requester\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n /// @notice A convenience function to make multiple authorization status\n /// checks with a single call\n /// @param authorizers Authorizer contract addresses\n /// @param airnode Airnode address\n /// @param requestIds Request IDs\n /// @param endpointIds Endpoint IDs\n /// @param sponsors Sponsor addresses\n /// @param requesters Requester addresses\n /// @return statuses Authorization statuses of the request\n function checkAuthorizationStatuses(\n address[] calldata authorizers,\n address airnode,\n bytes32[] calldata requestIds,\n bytes32[] calldata endpointIds,\n address[] calldata sponsors,\n address[] calldata requesters\n ) external view override returns (bool[] memory statuses) {\n require(\n requestIds.length == endpointIds.length &&\n requestIds.length == sponsors.length &&\n requestIds.length == requesters.length,\n \"Unequal parameter lengths\"\n );\n statuses = new bool[](requestIds.length);\n for (uint256 ind = 0; ind < requestIds.length; ind++) {\n statuses[ind] = checkAuthorizationStatus(\n authorizers,\n airnode,\n requestIds[ind],\n endpointIds[ind],\n sponsors[ind],\n requesters[ind]\n );\n }\n }\n}\n" + }, + "contracts/rrp/interfaces/IAirnodeRrpV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IAuthorizationUtilsV0.sol\";\nimport \"./ITemplateUtilsV0.sol\";\nimport \"./IWithdrawalUtilsV0.sol\";\n\ninterface IAirnodeRrpV0 is\n IAuthorizationUtilsV0,\n ITemplateUtilsV0,\n IWithdrawalUtilsV0\n{\n event SetSponsorshipStatus(\n address indexed sponsor,\n address indexed requester,\n bool sponsorshipStatus\n );\n\n event MadeTemplateRequest(\n address indexed airnode,\n bytes32 indexed requestId,\n uint256 requesterRequestCount,\n uint256 chainId,\n address requester,\n bytes32 templateId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes parameters\n );\n\n event MadeFullRequest(\n address indexed airnode,\n bytes32 indexed requestId,\n uint256 requesterRequestCount,\n uint256 chainId,\n address requester,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes parameters\n );\n\n event FulfilledRequest(\n address indexed airnode,\n bytes32 indexed requestId,\n bytes data\n );\n\n event FailedRequest(\n address indexed airnode,\n bytes32 indexed requestId,\n string errorMessage\n );\n\n function setSponsorshipStatus(address requester, bool sponsorshipStatus)\n external;\n\n function makeTemplateRequest(\n bytes32 templateId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external returns (bytes32 requestId);\n\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external returns (bytes32 requestId);\n\n function fulfill(\n bytes32 requestId,\n address airnode,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata data,\n bytes calldata signature\n ) external returns (bool callSuccess, bytes memory callData);\n\n function fail(\n bytes32 requestId,\n address airnode,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n string calldata errorMessage\n ) external;\n\n function sponsorToRequesterToSponsorshipStatus(\n address sponsor,\n address requester\n ) external view returns (bool sponsorshipStatus);\n\n function requesterToRequestCountPlusOne(address requester)\n external\n view\n returns (uint256 requestCountPlusOne);\n\n function requestIsAwaitingFulfillment(bytes32 requestId)\n external\n view\n returns (bool isAwaitingFulfillment);\n}\n" + }, + "contracts/rrp/interfaces/IAuthorizationUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IAuthorizationUtilsV0 {\n function checkAuthorizationStatus(\n address[] calldata authorizers,\n address airnode,\n bytes32 requestId,\n bytes32 endpointId,\n address sponsor,\n address requester\n ) external view returns (bool status);\n\n function checkAuthorizationStatuses(\n address[] calldata authorizers,\n address airnode,\n bytes32[] calldata requestIds,\n bytes32[] calldata endpointIds,\n address[] calldata sponsors,\n address[] calldata requesters\n ) external view returns (bool[] memory statuses);\n}\n" + }, + "contracts/rrp/interfaces/ITemplateUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ITemplateUtilsV0 {\n event CreatedTemplate(\n bytes32 indexed templateId,\n address airnode,\n bytes32 endpointId,\n bytes parameters\n );\n\n function createTemplate(\n address airnode,\n bytes32 endpointId,\n bytes calldata parameters\n ) external returns (bytes32 templateId);\n\n function getTemplates(bytes32[] calldata templateIds)\n external\n view\n returns (\n address[] memory airnodes,\n bytes32[] memory endpointIds,\n bytes[] memory parameters\n );\n\n function templates(bytes32 templateId)\n external\n view\n returns (\n address airnode,\n bytes32 endpointId,\n bytes memory parameters\n );\n}\n" + }, + "contracts/rrp/interfaces/IWithdrawalUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWithdrawalUtilsV0 {\n event RequestedWithdrawal(\n address indexed airnode,\n address indexed sponsor,\n bytes32 indexed withdrawalRequestId,\n address sponsorWallet\n );\n\n event FulfilledWithdrawal(\n address indexed airnode,\n address indexed sponsor,\n bytes32 indexed withdrawalRequestId,\n address sponsorWallet,\n uint256 amount\n );\n\n function requestWithdrawal(address airnode, address sponsorWallet) external;\n\n function fulfillWithdrawal(\n bytes32 withdrawalRequestId,\n address airnode,\n address sponsor\n ) external payable;\n\n function sponsorToWithdrawalRequestCount(address sponsor)\n external\n view\n returns (uint256 withdrawalRequestCount);\n}\n" + }, + "contracts/rrp/requesters/interfaces/IRrpBeaconServerV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../../whitelist/interfaces/IWhitelistWithManager.sol\";\n\ninterface IRrpBeaconServerV0 is IWhitelistWithManager {\n event SetUpdatePermissionStatus(\n address indexed sponsor,\n address indexed updateRequester,\n bool status\n );\n\n event RequestedBeaconUpdate(\n bytes32 indexed beaconId,\n address indexed sponsor,\n address indexed requester,\n bytes32 requestId,\n bytes32 templateId,\n address sponsorWallet,\n bytes parameters\n );\n\n event UpdatedBeacon(\n bytes32 indexed beaconId,\n bytes32 requestId,\n int224 value,\n uint32 timestamp\n );\n\n function setUpdatePermissionStatus(address updateRequester, bool status)\n external;\n\n function requestBeaconUpdate(\n bytes32 beaconId,\n address requester,\n address designatedWallet,\n bytes calldata parameters\n ) external;\n\n function fulfill(bytes32 requestId, bytes calldata data) external;\n\n function readBeacon(bytes32 beaconId)\n external\n view\n returns (int224 value, uint32 timestamp);\n\n function readerCanReadBeacon(bytes32 beaconId, address reader)\n external\n view\n returns (bool);\n\n function beaconIdToReaderToWhitelistStatus(bytes32 beaconId, address reader)\n external\n view\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount);\n\n function beaconIdToReaderToSetterToIndefiniteWhitelistStatus(\n bytes32 beaconId,\n address reader,\n address setter\n ) external view returns (bool indefiniteWhitelistStatus);\n\n function sponsorToUpdateRequesterToPermissionStatus(\n address sponsor,\n address updateRequester\n ) external view returns (bool permissionStatus);\n\n function deriveBeaconId(bytes32 templateId, bytes calldata parameters)\n external\n pure\n returns (bytes32 beaconId);\n}\n" + }, + "contracts/rrp/requesters/mock/MockRrpRequesterV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../RrpRequesterV0.sol\";\n\n/// @title A mock Airnode RRP requester contract\ncontract MockRrpRequesterV0 is RrpRequesterV0 {\n event FulfilledRequest(bytes32 indexed requestId, bytes data);\n\n mapping(bytes32 => bytes) public requestIdToData;\n\n mapping(bytes32 => bool) private expectingRequestWithIdToBeFulfilled;\n\n /// @param airnodeRrpAddress Airnode RRP contract address\n constructor(address airnodeRrpAddress) RrpRequesterV0(airnodeRrpAddress) {}\n\n /// @notice A wrapper for the respective method at AirnodeRrp.sol for\n /// testing\n /// @param templateId Template ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill\n /// the request\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @param parameters Parameters provided by the requester in addition to\n /// the parameters in the template\n function makeTemplateRequest(\n bytes32 templateId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external {\n bytes32 requestId = airnodeRrp.makeTemplateRequest(\n templateId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n );\n expectingRequestWithIdToBeFulfilled[requestId] = true;\n }\n\n /// @notice A wrapper for the respective method at AirnodeRrp.sol for\n /// testing\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill\n /// the request\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @param parameters All request parameters\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external {\n bytes32 requestId = airnodeRrp.makeFullRequest(\n airnode,\n endpointId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n );\n expectingRequestWithIdToBeFulfilled[requestId] = true;\n }\n\n /// @notice A method to be called back by the respective method at\n /// AirnodeRrp.sol for testing\n /// @param requestId Request ID\n /// @param data Data returned by the Airnode\n function fulfill(bytes32 requestId, bytes calldata data)\n external\n onlyAirnodeRrp\n {\n require(\n expectingRequestWithIdToBeFulfilled[requestId],\n \"No such request made\"\n );\n delete expectingRequestWithIdToBeFulfilled[requestId];\n requestIdToData[requestId] = data;\n emit FulfilledRequest(requestId, data);\n }\n\n /// @notice A method to be called back by the respective method at\n /// AirnodeRrp.sol for testing fulfillment failure\n /// @param requestId Request ID\n /// @param data Data returned by the Airnode\n function fulfillAlwaysReverts(\n bytes32 requestId, // solhint-disable-line no-unused-vars\n bytes calldata data // solhint-disable-line no-unused-vars\n ) external view onlyAirnodeRrp {\n revert(\"Always reverts\");\n }\n\n /// @notice A method to be called back by the respective method at\n /// AirnodeRrp.sol for testing fulfillment failure\n /// @param requestId Request ID\n /// @param data Data returned by the Airnode\n function fulfillAlwaysRevertsWithNoString(\n bytes32 requestId, // solhint-disable-line no-unused-vars\n bytes calldata data // solhint-disable-line no-unused-vars\n ) external view onlyAirnodeRrp {\n revert(); // solhint-disable-line reason-string\n }\n\n /// @notice A method to be called back by the respective method at\n /// AirnodeRrp.sol for testing fulfillment running out of gas\n /// @param requestId Request ID\n /// @param data Data returned by the Airnode\n function fulfillAlwaysRunsOutOfGas(\n bytes32 requestId, // solhint-disable-line no-unused-vars\n bytes calldata data // solhint-disable-line no-unused-vars\n ) external view onlyAirnodeRrp {\n while (true) {}\n }\n\n /// @notice A wrapper for the respective method at AirnodeRrp.sol for\n /// testing\n /// @dev The withdrawal requested by calling this will revert because this\n /// contract does not implement a default payable method\n /// @param airnode Airnode address\n /// @param sponsorWallet Sponsor wallet that the withdrawal is requested\n /// from\n function requestWithdrawal(address airnode, address sponsorWallet)\n external\n {\n airnodeRrp.requestWithdrawal(airnode, sponsorWallet);\n }\n}\n" + }, + "contracts/rrp/requesters/RrpBeaconServerV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../../whitelist/WhitelistWithManager.sol\";\nimport \"./RrpRequesterV0.sol\";\nimport \"./interfaces/IRrpBeaconServerV0.sol\";\n\n/// @title The contract that serves beacons using Airnode RRP\n/// @notice A beacon is a live data point associated with a beacon ID, which is\n/// derived from a template ID and additional parameters. This is suitable\n/// where the more recent data point is always more favorable, e.g., in the\n/// context of an asset price data feed. Another definition of beacons are\n/// one-Airnode data feeds that can be used individually or combined to build\n/// decentralized data feeds.\n/// @dev This contract casts the reported data point to `int224`. If this is\n/// a problem (because the reported data may not fit into 224 bits or it is of\n/// a completely different type such as `bytes32`), do not use this contract\n/// and implement a customized version instead.\n/// The contract casts the timestamps to `uint32`, which means it will not work\n/// work past-2106 in the current form. If this is an issue, consider casting\n/// the timestamps to a larger type.\ncontract RrpBeaconServerV0 is\n WhitelistWithManager,\n RrpRequesterV0,\n IRrpBeaconServerV0\n{\n struct Beacon {\n int224 value;\n uint32 timestamp;\n }\n\n /// @notice Returns if a sponsor has permitted an account to request\n /// updates at this contract\n mapping(address => mapping(address => bool))\n public\n override sponsorToUpdateRequesterToPermissionStatus;\n\n mapping(bytes32 => Beacon) private beacons;\n mapping(bytes32 => bytes32) private requestIdToBeaconId;\n\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n /// @param _manager Manager address\n /// @param _airnodeRrp Airnode RRP contract address\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription,\n address _manager,\n address _airnodeRrp\n )\n WhitelistWithManager(\n _accessControlRegistry,\n _adminRoleDescription,\n _manager\n )\n RrpRequesterV0(_airnodeRrp)\n {}\n\n /// @notice Called by the sponsor to set the update request permission\n /// status of an account\n /// @param updateRequester Update requester address\n /// @param status Update permission status of the update requester\n function setUpdatePermissionStatus(address updateRequester, bool status)\n external\n override\n {\n require(updateRequester != address(0), \"Update requester zero\");\n sponsorToUpdateRequesterToPermissionStatus[msg.sender][\n updateRequester\n ] = status;\n emit SetUpdatePermissionStatus(msg.sender, updateRequester, status);\n }\n\n /// @notice Called to request a beacon to be updated\n /// @dev There are two requirements for this method to be called: (1) The\n /// sponsor must call `setSponsorshipStatus()` of AirnodeRrp to sponsor\n /// this RrpBeaconServer contract, (2) The sponsor must call\n /// `setUpdatePermissionStatus()` of this RrpBeaconServer contract to give\n /// request update permission to the caller of this method.\n /// The template and additional parameters used here must specify a single\n /// point of data of type `int256` and an additional timestamp of type\n /// `uint256` to be returned because this is what `fulfill()` expects.\n /// This point of data must be castable to `int224` and the timestamp must\n /// be castable to `uint32`.\n /// @param templateId Template ID of the beacon to be updated\n /// @param sponsor Sponsor whose wallet will be used to fulfill this\n /// request\n /// @param sponsorWallet Sponsor wallet that will be used to fulfill this\n /// request\n /// @param parameters Parameters provided by the requester in addition to\n /// the parameters in the template\n function requestBeaconUpdate(\n bytes32 templateId,\n address sponsor,\n address sponsorWallet,\n bytes calldata parameters\n ) external override {\n require(\n sponsorToUpdateRequesterToPermissionStatus[sponsor][msg.sender],\n \"Caller not permitted\"\n );\n bytes32 beaconId = deriveBeaconId(templateId, parameters);\n bytes32 requestId = airnodeRrp.makeTemplateRequest(\n templateId,\n sponsor,\n sponsorWallet,\n address(this),\n this.fulfill.selector,\n parameters\n );\n requestIdToBeaconId[requestId] = beaconId;\n emit RequestedBeaconUpdate(\n beaconId,\n sponsor,\n msg.sender,\n requestId,\n templateId,\n sponsorWallet,\n parameters\n );\n }\n\n /// @notice Called by AirnodeRrp to fulfill the request\n /// @dev It is assumed that the fulfillment will be made with a single\n /// point of data of type `int256` and an additional timestamp of type\n /// `uint256`\n /// @param requestId ID of the request being fulfilled\n /// @param data Fulfillment data (a single `int256` and an additional\n /// timestamp of type `uint256` encoded as `bytes`)\n function fulfill(bytes32 requestId, bytes calldata data)\n external\n override\n onlyAirnodeRrp\n {\n bytes32 beaconId = requestIdToBeaconId[requestId];\n require(beaconId != bytes32(0), \"No such request made\");\n delete requestIdToBeaconId[requestId];\n (int256 decodedData, uint256 decodedTimestamp) = abi.decode(\n data,\n (int256, uint256)\n );\n require(\n decodedData >= type(int224).min && decodedData <= type(int224).max,\n \"Value typecasting error\"\n );\n require(\n decodedTimestamp <= type(uint32).max,\n \"Timestamp typecasting error\"\n );\n require(\n decodedTimestamp > beacons[beaconId].timestamp,\n \"Fulfillment older than beacon\"\n );\n require(\n decodedTimestamp + 1 hours > block.timestamp,\n \"Fulfillment stale\"\n );\n require(\n decodedTimestamp - 1 hours < block.timestamp,\n \"Fulfillment from future\"\n );\n beacons[beaconId] = Beacon({\n value: int224(decodedData),\n timestamp: uint32(decodedTimestamp)\n });\n emit UpdatedBeacon(\n beaconId,\n requestId,\n int224(decodedData),\n uint32(decodedTimestamp)\n );\n }\n\n /// @notice Called to read the beacon\n /// @dev The caller must be whitelisted.\n /// If the `timestamp` of a beacon is zero, this means that it was never\n /// written to before, and the zero value in the `value` field is not\n /// valid. In general, make sure to check if the timestamp of the beacon is\n /// fresh enough, and definitely disregard beacons with zero `timestamp`.\n /// @param beaconId ID of the beacon that will be returned\n /// @return value Beacon value\n /// @return timestamp Beacon timestamp\n function readBeacon(bytes32 beaconId)\n external\n view\n override\n returns (int224 value, uint32 timestamp)\n {\n require(\n readerCanReadBeacon(beaconId, msg.sender),\n \"Caller not whitelisted\"\n );\n Beacon storage beacon = beacons[beaconId];\n return (beacon.value, beacon.timestamp);\n }\n\n /// @notice Called to check if a reader is whitelisted to read the beacon\n /// @param beaconId Beacon ID\n /// @param reader Reader address\n /// @return isWhitelisted If the reader is whitelisted\n function readerCanReadBeacon(bytes32 beaconId, address reader)\n public\n view\n override\n returns (bool)\n {\n return userIsWhitelisted(beaconId, reader) || reader == address(0);\n }\n\n /// @notice Called to get the detailed whitelist status of the reader for\n /// the beacon\n /// @param beaconId Beacon ID\n /// @param reader Reader address\n /// @return expirationTimestamp Timestamp at which the whitelisting of the\n /// reader will expire\n /// @return indefiniteWhitelistCount Number of times `reader` was\n /// whitelisted indefinitely for `templateId`\n function beaconIdToReaderToWhitelistStatus(bytes32 beaconId, address reader)\n external\n view\n override\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount)\n {\n WhitelistStatus\n storage whitelistStatus = serviceIdToUserToWhitelistStatus[\n beaconId\n ][reader];\n expirationTimestamp = whitelistStatus.expirationTimestamp;\n indefiniteWhitelistCount = whitelistStatus.indefiniteWhitelistCount;\n }\n\n /// @notice Returns if an account has indefinitely whitelisted the reader\n /// for the beacon\n /// @param beaconId Beacon ID\n /// @param reader Reader address\n /// @param setter Address of the account that has potentially whitelisted\n /// the reader for the beacon indefinitely\n /// @return indefiniteWhitelistStatus If `setter` has indefinitely\n /// whitelisted reader for the beacon\n function beaconIdToReaderToSetterToIndefiniteWhitelistStatus(\n bytes32 beaconId,\n address reader,\n address setter\n ) external view override returns (bool indefiniteWhitelistStatus) {\n indefiniteWhitelistStatus = serviceIdToUserToSetterToIndefiniteWhitelistStatus[\n beaconId\n ][reader][setter];\n }\n\n /// @notice Derives the beacon ID from the respective template ID and\n /// additional parameters\n /// @param templateId Template ID\n /// @param parameters Parameters provided by the requester in addition to\n /// the parameters in the template\n /// @return beaconId Beacon ID\n function deriveBeaconId(bytes32 templateId, bytes calldata parameters)\n public\n pure\n override\n returns (bytes32 beaconId)\n {\n beaconId = keccak256(abi.encodePacked(templateId, parameters));\n }\n}\n" + }, + "contracts/rrp/requesters/RrpRequesterV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/IAirnodeRrpV0.sol\";\n\n/// @title The contract to be inherited to make Airnode RRP requests\ncontract RrpRequesterV0 {\n IAirnodeRrpV0 public immutable airnodeRrp;\n\n /// @dev Reverts if the caller is not the Airnode RRP contract.\n /// Use it as a modifier for fulfill and error callback methods, but also\n /// check `requestId`.\n modifier onlyAirnodeRrp() {\n require(msg.sender == address(airnodeRrp), \"Caller not Airnode RRP\");\n _;\n }\n\n /// @dev Airnode RRP address is set at deployment and is immutable.\n /// RrpRequester is made its own sponsor by default. RrpRequester can also\n /// be sponsored by others and use these sponsorships while making\n /// requests, i.e., using this default sponsorship is optional.\n /// @param _airnodeRrp Airnode RRP contract address\n constructor(address _airnodeRrp) {\n airnodeRrp = IAirnodeRrpV0(_airnodeRrp);\n IAirnodeRrpV0(_airnodeRrp).setSponsorshipStatus(address(this), true);\n }\n}\n" + }, + "contracts/rrp/TemplateUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interfaces/ITemplateUtilsV0.sol\";\n\n/// @title Contract that implements request templates\ncontract TemplateUtilsV0 is ITemplateUtilsV0 {\n struct Template {\n address airnode;\n bytes32 endpointId;\n bytes parameters;\n }\n\n /// @notice Called to get a template\n mapping(bytes32 => Template) public override templates;\n\n /// @notice Creates a request template with the given parameters,\n /// addressable by the ID it returns\n /// @dev A specific set of request parameters will always have the same\n /// template ID. This means a few things: (1) You can compute the expected\n /// ID of a template before creating it, (2) Creating a new template with\n /// the same parameters will overwrite the old one and return the same ID,\n /// (3) After you query a template with its ID, you can verify its\n /// integrity by applying the hash and comparing the result with the ID.\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param parameters Static request parameters (i.e., parameters that will\n /// not change between requests, unlike the dynamic parameters determined\n /// at request-time)\n /// @return templateId Request template ID\n function createTemplate(\n address airnode,\n bytes32 endpointId,\n bytes calldata parameters\n ) external override returns (bytes32 templateId) {\n require(airnode != address(0), \"Airnode address zero\");\n templateId = keccak256(\n abi.encodePacked(airnode, endpointId, parameters)\n );\n templates[templateId] = Template({\n airnode: airnode,\n endpointId: endpointId,\n parameters: parameters\n });\n emit CreatedTemplate(templateId, airnode, endpointId, parameters);\n }\n\n /// @notice A convenience method to retrieve multiple templates with a\n /// single call\n /// @dev Does not revert if the templates being indexed do not exist\n /// @param templateIds Request template IDs\n /// @return airnodes Array of Airnode addresses\n /// @return endpointIds Array of endpoint IDs\n /// @return parameters Array of request parameters\n function getTemplates(bytes32[] calldata templateIds)\n external\n view\n override\n returns (\n address[] memory airnodes,\n bytes32[] memory endpointIds,\n bytes[] memory parameters\n )\n {\n airnodes = new address[](templateIds.length);\n endpointIds = new bytes32[](templateIds.length);\n parameters = new bytes[](templateIds.length);\n for (uint256 ind = 0; ind < templateIds.length; ind++) {\n Template storage template = templates[templateIds[ind]];\n airnodes[ind] = template.airnode;\n endpointIds[ind] = template.endpointId;\n parameters[ind] = template.parameters;\n }\n }\n}\n" + }, + "contracts/rrp/WithdrawalUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interfaces/IWithdrawalUtilsV0.sol\";\n\n/// @title Contract that implements logic for withdrawals from sponsor wallets\ncontract WithdrawalUtilsV0 is IWithdrawalUtilsV0 {\n /// @notice Called to get the withdrawal request count of the sponsor\n /// @dev Can be used to calculate the ID of the next withdrawal request the\n /// sponsor will make\n mapping(address => uint256) public override sponsorToWithdrawalRequestCount;\n\n /// @dev Hash of expected fulfillment parameters are kept to verify that\n /// the fulfillment will be done with the correct parameters\n mapping(bytes32 => bytes32) private withdrawalRequestIdToParameters;\n\n /// @notice Called by a sponsor to create a request for the Airnode to send\n /// the funds kept in the respective sponsor wallet to the sponsor\n /// @dev We do not need to use the withdrawal request parameters in the\n /// request ID hash to validate them at the node-side because all of the\n /// parameters are used during fulfillment and will get validated on-chain.\n /// The first withdrawal request a sponsor will make will cost slightly\n /// higher gas than the rest due to how the request counter is implemented.\n /// @param airnode Airnode address\n /// @param sponsorWallet Sponsor wallet that the withdrawal is requested\n /// from\n function requestWithdrawal(address airnode, address sponsorWallet)\n external\n override\n {\n bytes32 withdrawalRequestId = keccak256(\n abi.encodePacked(\n block.chainid,\n address(this),\n msg.sender,\n ++sponsorToWithdrawalRequestCount[msg.sender]\n )\n );\n withdrawalRequestIdToParameters[withdrawalRequestId] = keccak256(\n abi.encodePacked(airnode, msg.sender, sponsorWallet)\n );\n emit RequestedWithdrawal(\n airnode,\n msg.sender,\n withdrawalRequestId,\n sponsorWallet\n );\n }\n\n /// @notice Called by the Airnode using the sponsor wallet to fulfill the\n /// withdrawal request made by the sponsor\n /// @dev The Airnode sends the funds to the sponsor through this method\n /// to emit an event that indicates that the withdrawal request has been\n /// fulfilled\n /// @param withdrawalRequestId Withdrawal request ID\n /// @param airnode Airnode address\n /// @param sponsor Sponsor address\n function fulfillWithdrawal(\n bytes32 withdrawalRequestId,\n address airnode,\n address sponsor\n ) external payable override {\n require(\n withdrawalRequestIdToParameters[withdrawalRequestId] ==\n keccak256(abi.encodePacked(airnode, sponsor, msg.sender)),\n \"Invalid withdrawal fulfillment\"\n );\n delete withdrawalRequestIdToParameters[withdrawalRequestId];\n emit FulfilledWithdrawal(\n airnode,\n sponsor,\n withdrawalRequestId,\n msg.sender,\n msg.value\n );\n (bool success, ) = sponsor.call{value: msg.value}(\"\"); // solhint-disable-line avoid-low-level-calls\n require(success, \"Transfer failed\");\n }\n}\n" + }, + "contracts/utils/interfaces/IOwnableCallForwarder.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IOwnableCallForwarder {\n function forwardCall(\n address forwardTarget,\n bytes calldata forwardedCalldata\n ) external payable returns (bytes memory returnedData);\n}\n" + }, + "contracts/utils/mock/MockCallForwarderTarget.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\ncontract MockCallForwarderTarget {\n string public storage1;\n uint256 public storage2;\n\n function payableTargetFunction(\n string calldata input1,\n uint256 input2,\n uint256 msgValue\n ) external payable returns (bytes memory output1, bool output2) {\n require(\n keccak256(abi.encodePacked(input1)) ==\n keccak256(abi.encodePacked(\"input1\")),\n \"Incorrect input\"\n );\n require(input2 == 123, \"Incorrect input\");\n require(msg.value == msgValue, \"Incorrect value\");\n storage1 = input1;\n storage2 = input2;\n output1 = hex\"12345678\";\n output2 = true;\n }\n\n function nonpayableTargetFunction(string calldata input1, uint256 input2)\n external\n returns (bytes memory output1, bool output2)\n {\n require(\n keccak256(abi.encodePacked(input1)) ==\n keccak256(abi.encodePacked(\"input1\")),\n \"Incorrect input\"\n );\n require(input2 == 123, \"Incorrect input\");\n storage1 = input1;\n storage2 = input2;\n output1 = hex\"12345678\";\n output2 = true;\n }\n}\n" + }, + "contracts/utils/OwnableCallForwarder.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/IOwnableCallForwarder.sol\";\n\n/// @title Contract that forwards the calls that its owner sends\n/// @dev AccessControlRegistry users that want their access control tables\n/// to be transferrable (e.g., a DAO) will use this forwarder instead of\n/// interacting with it directly. There are cases where this transferrability\n/// is not desired, e.g., if the user is an Airnode and is immutably associated\n/// with a single address, in which case the manager will interact with\n/// AccessControlRegistry directly.\n/// The ownership of this contract is deliberately renouncable. If this does\n/// suit the use case, override and disable this functionality.\ncontract OwnableCallForwarder is Ownable, IOwnableCallForwarder {\n /// @notice Forwards the calldata and the value to the target address if\n /// the sender is the owner and returns the data\n /// @param forwardTarget Target address that the calldata will be forwarded\n /// to\n /// @param forwardedCalldata Calldata to be forwarded to the target address\n /// @return returnedData Data returned by the forwarded call\n function forwardCall(\n address forwardTarget,\n bytes calldata forwardedCalldata\n ) external payable override onlyOwner returns (bytes memory returnedData) {\n returnedData = Address.functionCallWithValue(\n forwardTarget,\n forwardedCalldata,\n msg.value\n );\n }\n}\n" + }, + "contracts/whitelist/interfaces/IWhitelistRoles.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWhitelistRoles {\n // solhint-disable-next-line func-name-mixedcase\n function WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION()\n external\n view\n returns (string memory);\n\n // solhint-disable-next-line func-name-mixedcase\n function WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION()\n external\n view\n returns (string memory);\n\n // solhint-disable-next-line func-name-mixedcase\n function INDEFINITE_WHITELISTER_ROLE_DESCRIPTION()\n external\n view\n returns (string memory);\n}\n" + }, + "contracts/whitelist/interfaces/IWhitelistRolesWithAirnode.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IWhitelistRoles.sol\";\nimport \"../../access-control-registry/interfaces/IAccessControlRegistryAdminned.sol\";\n\ninterface IWhitelistRolesWithAirnode is\n IWhitelistRoles,\n IAccessControlRegistryAdminned\n{\n function deriveAdminRole(address airnode)\n external\n view\n returns (bytes32 role);\n\n function deriveWhitelistExpirationExtenderRole(address airnode)\n external\n view\n returns (bytes32 role);\n\n function deriveWhitelistExpirationSetterRole(address airnode)\n external\n view\n returns (bytes32 role);\n\n function deriveIndefiniteWhitelisterRole(address airnode)\n external\n view\n returns (bytes32 role);\n}\n" + }, + "contracts/whitelist/interfaces/IWhitelistRolesWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IWhitelistRoles.sol\";\nimport \"../../access-control-registry/interfaces/IAccessControlRegistryAdminnedWithManager.sol\";\n\ninterface IWhitelistRolesWithManager is\n IWhitelistRoles,\n IAccessControlRegistryAdminnedWithManager\n{\n function whitelistExpirationExtenderRole() external view returns (bytes32);\n\n function whitelistExpirationSetterRole() external view returns (bytes32);\n\n function indefiniteWhitelisterRole() external view returns (bytes32);\n}\n" + }, + "contracts/whitelist/interfaces/IWhitelistWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IWhitelistRolesWithManager.sol\";\n\ninterface IWhitelistWithManager is IWhitelistRolesWithManager {\n event ExtendedWhitelistExpiration(\n bytes32 indexed serviceId,\n address indexed user,\n address indexed sender,\n uint256 expiration\n );\n\n event SetWhitelistExpiration(\n bytes32 indexed serviceId,\n address indexed user,\n address indexed sender,\n uint256 expiration\n );\n\n event SetIndefiniteWhitelistStatus(\n bytes32 indexed serviceId,\n address indexed user,\n address indexed sender,\n bool status,\n uint192 indefiniteWhitelistCount\n );\n\n event RevokedIndefiniteWhitelistStatus(\n bytes32 indexed serviceId,\n address indexed user,\n address indexed setter,\n address sender,\n uint192 indefiniteWhitelistCount\n );\n\n function extendWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) external;\n\n function setWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) external;\n\n function setIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n bool status\n ) external;\n\n function revokeIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n address setter\n ) external;\n}\n" + }, + "contracts/whitelist/Whitelist.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Contract to be inherited by contracts that need temporary and\n/// permanent whitelists for services identified by hashes\n/// @notice This contract implements two kinds of whitelisting:\n/// (1) Temporary, ends when the expiration timestamp is in the past\n/// (2) Indefinite, ends when the indefinite whitelist count is zero\n/// Multiple senders can indefinitely whitelist/unwhitelist independently. The\n/// user will be considered whitelisted as long as there is at least one active\n/// indefinite whitelisting.\n/// @dev The interface of this contract is not implemented. It should be\n/// inherited and its functions should be exposed with a sort of an\n/// authorization scheme.\ncontract Whitelist {\n struct WhitelistStatus {\n uint64 expirationTimestamp;\n uint192 indefiniteWhitelistCount;\n }\n\n mapping(bytes32 => mapping(address => WhitelistStatus))\n internal serviceIdToUserToWhitelistStatus;\n\n mapping(bytes32 => mapping(address => mapping(address => bool)))\n internal serviceIdToUserToSetterToIndefiniteWhitelistStatus;\n\n /// @notice Extends the expiration of the temporary whitelist of the user\n /// for the service\n /// @param serviceId Service ID\n /// @param user User address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function _extendWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) internal {\n require(\n expirationTimestamp >\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .expirationTimestamp,\n \"Does not extend expiration\"\n );\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .expirationTimestamp = expirationTimestamp;\n }\n\n /// @notice Sets the expiration of the temporary whitelist of the user for\n /// the service\n /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration\n /// @param serviceId Service ID\n /// @param user User address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function _setWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) internal {\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .expirationTimestamp = expirationTimestamp;\n }\n\n /// @notice Sets the indefinite whitelist status of the user for the\n /// service\n /// @dev As long as at least there is at least one account that has set the\n /// indefinite whitelist status of the user for the service as true, the\n /// user will be considered whitelisted\n /// @param serviceId Service ID\n /// @param user User address\n /// @param status Indefinite whitelist status\n function _setIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n bool status\n ) internal returns (uint192 indefiniteWhitelistCount) {\n indefiniteWhitelistCount = serviceIdToUserToWhitelistStatus[serviceId][\n user\n ].indefiniteWhitelistCount;\n if (\n status &&\n !serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][\n user\n ][msg.sender]\n ) {\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\n msg.sender\n ] = true;\n indefiniteWhitelistCount++;\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\n } else if (\n !status &&\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\n msg.sender\n ]\n ) {\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\n msg.sender\n ] = false;\n indefiniteWhitelistCount--;\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\n }\n }\n\n /// @notice Revokes the indefinite whitelist status granted to the user for\n /// the service by a specific account\n /// @param serviceId Service ID\n /// @param user User address\n /// @param setter Setter of the indefinite whitelist status\n function _revokeIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n address setter\n ) internal returns (bool revoked, uint192 indefiniteWhitelistCount) {\n indefiniteWhitelistCount = serviceIdToUserToWhitelistStatus[serviceId][\n user\n ].indefiniteWhitelistCount;\n if (\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\n setter\n ]\n ) {\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\n setter\n ] = false;\n indefiniteWhitelistCount--;\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\n revoked = true;\n }\n }\n\n /// @notice Returns if the user is whitelised to use the service\n /// @param serviceId Service ID\n /// @param user User address\n /// @return isWhitelisted If the user is whitelisted\n function userIsWhitelisted(bytes32 serviceId, address user)\n internal\n view\n returns (bool isWhitelisted)\n {\n WhitelistStatus\n storage whitelistStatus = serviceIdToUserToWhitelistStatus[\n serviceId\n ][user];\n return\n whitelistStatus.indefiniteWhitelistCount > 0 ||\n whitelistStatus.expirationTimestamp > block.timestamp;\n }\n}\n" + }, + "contracts/whitelist/WhitelistRoles.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interfaces/IWhitelistRoles.sol\";\n\n/// @title Contract to be inherited by Whitelist contracts that will use\n/// generic AccessControlRegistry roles\ncontract WhitelistRoles is IWhitelistRoles {\n // There are four roles implemented in this contract:\n // Root\n // └── (1) Admin (can grant and revoke the roles below)\n // ├── (2) Whitelist expiration extender\n // ├── (3) Whitelist expiration setter\n // └── (4) Indefinite whitelister\n // Their IDs are derived from the descriptions below. Refer to\n // AccessControlRegistry for more information.\n // To clarify, the root role of the manager is the admin of (1), while (1)\n // is the admin of (2), (3) and (4). So (1) is more of a \"contract admin\",\n // while the `adminRole` used in AccessControl and AccessControlRegistry\n // refers to a more general adminship relationship between roles.\n\n /// @notice Whitelist expiration extender role description\n string\n public constant\n override WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION =\n \"Whitelist expiration extender\";\n\n /// @notice Whitelist expiration setter role description\n string\n public constant\n override WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION =\n \"Whitelist expiration setter\";\n\n /// @notice Indefinite whitelister role description\n\n string public constant override INDEFINITE_WHITELISTER_ROLE_DESCRIPTION =\n \"Indefinite whitelister\";\n\n bytes32\n internal constant WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH =\n keccak256(\n abi.encodePacked(WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION)\n );\n\n bytes32\n internal constant WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH =\n keccak256(\n abi.encodePacked(WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION)\n );\n\n bytes32 internal constant INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH =\n keccak256(abi.encodePacked(INDEFINITE_WHITELISTER_ROLE_DESCRIPTION));\n}\n" + }, + "contracts/whitelist/WhitelistRolesWithAirnode.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./WhitelistRoles.sol\";\nimport \"../access-control-registry/AccessControlRegistryAdminned.sol\";\nimport \"./interfaces/IWhitelistRolesWithAirnode.sol\";\nimport \"../access-control-registry/interfaces/IAccessControlRegistry.sol\";\n\n/// @title Contract to be inherited by Whitelist contracts that will use\n/// roles where each individual Airnode address is its own manager\ncontract WhitelistRolesWithAirnode is\n WhitelistRoles,\n AccessControlRegistryAdminned,\n IWhitelistRolesWithAirnode\n{\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription\n )\n AccessControlRegistryAdminned(\n _accessControlRegistry,\n _adminRoleDescription\n )\n {}\n\n /// @notice Derives the admin role for the Airnode\n /// @param airnode Airnode address\n /// @return adminRole Admin role\n function deriveAdminRole(address airnode)\n external\n view\n override\n returns (bytes32 adminRole)\n {\n adminRole = _deriveAdminRole(airnode);\n }\n\n /// @notice Derives the whitelist expiration extender role for the Airnode\n /// @param airnode Airnode address\n /// @return whitelistExpirationExtenderRole Whitelist expiration extender\n /// role\n function deriveWhitelistExpirationExtenderRole(address airnode)\n public\n view\n override\n returns (bytes32 whitelistExpirationExtenderRole)\n {\n whitelistExpirationExtenderRole = _deriveRole(\n _deriveAdminRole(airnode),\n WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH\n );\n }\n\n /// @notice Derives the whitelist expiration setter role for the Airnode\n /// @param airnode Airnode address\n /// @return whitelistExpirationSetterRole Whitelist expiration setter role\n function deriveWhitelistExpirationSetterRole(address airnode)\n public\n view\n override\n returns (bytes32 whitelistExpirationSetterRole)\n {\n whitelistExpirationSetterRole = _deriveRole(\n _deriveAdminRole(airnode),\n WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH\n );\n }\n\n /// @notice Derives the indefinite whitelister role for the Airnode\n /// @param airnode Airnode address\n /// @return indefiniteWhitelisterRole Indefinite whitelister role\n function deriveIndefiniteWhitelisterRole(address airnode)\n public\n view\n override\n returns (bytes32 indefiniteWhitelisterRole)\n {\n indefiniteWhitelisterRole = _deriveRole(\n _deriveAdminRole(airnode),\n INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH\n );\n }\n\n /// @dev Returns if the account has the whitelist expiration extender role\n /// or is the Airnode address\n /// @param airnode Airnode address\n /// @param account Account address\n /// @return If the account has the whitelist extender role or is the\n /// Airnode address\n function hasWhitelistExpirationExtenderRoleOrIsAirnode(\n address airnode,\n address account\n ) internal view returns (bool) {\n return\n airnode == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n deriveWhitelistExpirationExtenderRole(airnode),\n account\n );\n }\n\n /// @dev Returns if the account has the whitelist expriation setter role or\n /// is the Airnode address\n /// @param airnode Airnode address\n /// @param account Account address\n /// @return If the account has the whitelist setter role or is the Airnode\n /// address\n function hasWhitelistExpirationSetterRoleOrIsAirnode(\n address airnode,\n address account\n ) internal view returns (bool) {\n return\n airnode == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n deriveWhitelistExpirationSetterRole(airnode),\n account\n );\n }\n\n /// @dev Returns if the account has the indefinite whitelister role or is the\n /// Airnode address\n /// @param airnode Airnode address\n /// @param account Account address\n /// @return If the account has the indefinite whitelister role or is the\n /// Airnode addrss\n function hasIndefiniteWhitelisterRoleOrIsAirnode(\n address airnode,\n address account\n ) internal view returns (bool) {\n return\n airnode == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n deriveIndefiniteWhitelisterRole(airnode),\n account\n );\n }\n}\n" + }, + "contracts/whitelist/WhitelistRolesWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./WhitelistRoles.sol\";\nimport \"../access-control-registry/AccessControlRegistryAdminnedWithManager.sol\";\nimport \"./interfaces/IWhitelistRolesWithManager.sol\";\nimport \"../access-control-registry/interfaces/IAccessControlRegistry.sol\";\n\n/// @title Contract to be inherited by Whitelist contracts that will use\n/// roles where there is a single manager\ncontract WhitelistRolesWithManager is\n WhitelistRoles,\n AccessControlRegistryAdminnedWithManager,\n IWhitelistRolesWithManager\n{\n // Since there will be a single manager, we can derive the roles beforehand\n\n /// @notice Whitelist expiration extender role\n bytes32 public immutable override whitelistExpirationExtenderRole;\n\n /// @notice Whitelist expiration setter role\n bytes32 public immutable override whitelistExpirationSetterRole;\n\n /// @notice Indefinite whitelister role\n bytes32 public immutable override indefiniteWhitelisterRole;\n\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n /// @param _manager Manager address\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription,\n address _manager\n )\n AccessControlRegistryAdminnedWithManager(\n _accessControlRegistry,\n _adminRoleDescription,\n _manager\n )\n {\n whitelistExpirationExtenderRole = _deriveRole(\n adminRole,\n WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH\n );\n whitelistExpirationSetterRole = _deriveRole(\n adminRole,\n WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH\n );\n indefiniteWhitelisterRole = _deriveRole(\n adminRole,\n INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH\n );\n }\n\n /// @dev Returns if the account has the whitelist expiration extender role\n /// or is the manager\n /// @param account Account address\n /// @return If the account has the whitelist extender role or is the\n /// manager\n function hasWhitelistExpirationExtenderRoleOrIsManager(address account)\n internal\n view\n returns (bool)\n {\n return\n manager == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n whitelistExpirationExtenderRole,\n account\n );\n }\n\n /// @dev Returns if the account has the whitelist expriation setter role or\n /// is the manager\n /// @param account Account address\n /// @return If the account has the whitelist setter role or is the\n /// manager\n function hasWhitelistExpirationSetterRoleOrIsManager(address account)\n internal\n view\n returns (bool)\n {\n return\n manager == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n whitelistExpirationSetterRole,\n account\n );\n }\n\n /// @dev Returns if the account has the indefinite whitelister role or is the\n /// manager\n /// @param account Account address\n /// @return If the account has the indefinite whitelister role or is the\n /// manager\n function hasIndefiniteWhitelisterRoleOrIsManager(address account)\n internal\n view\n returns (bool)\n {\n return\n manager == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n indefiniteWhitelisterRole,\n account\n );\n }\n}\n" + }, + "contracts/whitelist/WhitelistWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./Whitelist.sol\";\nimport \"./WhitelistRolesWithManager.sol\";\nimport \"./interfaces/IWhitelistWithManager.sol\";\n\n/// @title Contract to be inherited by Whitelist contracts that are controlled\n/// by a manager\ncontract WhitelistWithManager is\n Whitelist,\n WhitelistRolesWithManager,\n IWhitelistWithManager\n{\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n /// @param _manager Manager address\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription,\n address _manager\n )\n WhitelistRolesWithManager(\n _accessControlRegistry,\n _adminRoleDescription,\n _manager\n )\n {}\n\n /// @notice Extends the expiration of the temporary whitelist of `user` to\n /// be able to use the service with `serviceId` if the sender has the\n /// whitelist expiration extender role\n /// @param serviceId Service ID\n /// @param user User address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function extendWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationExtenderRoleOrIsManager(msg.sender),\n \"Cannot extend expiration\"\n );\n require(serviceId != bytes32(0), \"Service ID zero\");\n require(user != address(0), \"User address zero\");\n _extendWhitelistExpiration(serviceId, user, expirationTimestamp);\n emit ExtendedWhitelistExpiration(\n serviceId,\n user,\n msg.sender,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the expiration of the temporary whitelist of `user` to be\n /// able to use the service with `serviceId` if the sender has the\n /// whitelist expiration setter role\n /// @param serviceId Service ID\n /// @param user User address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function setWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationSetterRoleOrIsManager(msg.sender),\n \"Cannot set expiration\"\n );\n require(serviceId != bytes32(0), \"Service ID zero\");\n require(user != address(0), \"User address zero\");\n _setWhitelistExpiration(serviceId, user, expirationTimestamp);\n emit SetWhitelistExpiration(\n serviceId,\n user,\n msg.sender,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the indefinite whitelist status of `user` to be able to\n /// use the service with `serviceId` if the sender has the indefinite\n /// whitelister role\n /// @param serviceId Service ID\n /// @param user User address\n /// @param status Indefinite whitelist status\n function setIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n bool status\n ) external override {\n require(\n hasIndefiniteWhitelisterRoleOrIsManager(msg.sender),\n \"Cannot set indefinite status\"\n );\n require(serviceId != bytes32(0), \"Service ID zero\");\n require(user != address(0), \"User address zero\");\n uint192 indefiniteWhitelistCount = _setIndefiniteWhitelistStatus(\n serviceId,\n user,\n status\n );\n emit SetIndefiniteWhitelistStatus(\n serviceId,\n user,\n msg.sender,\n status,\n indefiniteWhitelistCount\n );\n }\n\n /// @notice Revokes the indefinite whitelist status granted by a specific\n /// account that no longer has the indefinite whitelister role\n /// @param serviceId Service ID\n /// @param user User address\n /// @param setter Setter of the indefinite whitelist status\n function revokeIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n address setter\n ) external override {\n require(\n !hasIndefiniteWhitelisterRoleOrIsManager(setter),\n \"setter can set indefinite status\"\n );\n (\n bool revoked,\n uint192 indefiniteWhitelistCount\n ) = _revokeIndefiniteWhitelistStatus(serviceId, user, setter);\n if (revoked) {\n emit RevokedIndefiniteWhitelistStatus(\n serviceId,\n user,\n setter,\n msg.sender,\n indefiniteWhitelistCount\n );\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/packages/airnode-protocol/deployments/references.json b/packages/airnode-protocol/deployments/references.json index 8227961d10..18dfa3f0d4 100644 --- a/packages/airnode-protocol/deployments/references.json +++ b/packages/airnode-protocol/deployments/references.json @@ -21,6 +21,7 @@ "1285": "moonriver", "1287": "moonbeam-testnet", "1442": "polygon-zkevm-goerli-testnet", + "1891": "lightlink-goerli-testnet", "2001": "milkomeda-c1", "4002": "fantom-testnet", "5000": "mantle", @@ -67,6 +68,7 @@ "1285": "0x92E5125adF385d86beDb950793526106143b6Df1", "1287": "0x92E5125adF385d86beDb950793526106143b6Df1", "1442": "0x92E5125adF385d86beDb950793526106143b6Df1", + "1891": "0x92E5125adF385d86beDb950793526106143b6Df1", "2001": "0x92E5125adF385d86beDb950793526106143b6Df1", "4002": "0x92E5125adF385d86beDb950793526106143b6Df1", "5000": "0x92E5125adF385d86beDb950793526106143b6Df1", @@ -113,6 +115,7 @@ "1285": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "1287": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "1442": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "1891": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "2001": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "4002": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "5000": "0xf18c105D0375E80980e4EED829a4A68A539E6178", @@ -159,6 +162,7 @@ "1285": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "1287": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "1442": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "1891": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "2001": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "4002": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "5000": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", @@ -205,6 +209,7 @@ "1285": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "1287": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "1442": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "1891": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "2001": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "4002": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "5000": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", @@ -314,6 +319,10 @@ "chainId": 1442, "name": "polygon-zkevm-goerli-testnet" }, + "1891": { + "chainId": 1891, + "name": "lightlink-goerli-testnet" + }, "2001": { "chainId": 2001, "name": "milkomeda-c1" From d22d4dfb1062d2aa5c11f771f80906b1eba678a6 Mon Sep 17 00:00:00 2001 From: Vansh Wassan <007blackhacker@gmail.com> Date: Fri, 8 Dec 2023 08:14:50 +0530 Subject: [PATCH 2/9] added changeset --- .changeset/large-glasses-learn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/large-glasses-learn.md diff --git a/.changeset/large-glasses-learn.md b/.changeset/large-glasses-learn.md new file mode 100644 index 0000000000..f9646d8dc8 --- /dev/null +++ b/.changeset/large-glasses-learn.md @@ -0,0 +1,5 @@ +--- +'@api3/airnode-protocol': minor +--- + +deploy protocol contracts on lightlink-goerli-testnet From 2289095fc486deb080b403f3d6f3d229b543fd3c Mon Sep 17 00:00:00 2001 From: Vansh Wassan <007blackhacker@gmail.com> Date: Fri, 8 Dec 2023 08:42:45 +0530 Subject: [PATCH 3/9] Deployed protocol contracts on lightlink --- .../deployments/lightlink/.chainId | 1 + .../lightlink/AccessControlRegistry.json | 535 ++++++++ .../deployments/lightlink/AirnodeRrpV0.json | 1184 +++++++++++++++++ .../lightlink/AirnodeRrpV0DryRun.json | 163 +++ .../RequesterAuthorizerWithAirnode.json | 912 +++++++++++++ .../d8591a026515856ab7bc7dc284bf2fbe.json | 189 +++ .../deployments/references.json | 9 + 7 files changed, 2993 insertions(+) create mode 100644 packages/airnode-protocol/deployments/lightlink/.chainId create mode 100644 packages/airnode-protocol/deployments/lightlink/AccessControlRegistry.json create mode 100644 packages/airnode-protocol/deployments/lightlink/AirnodeRrpV0.json create mode 100644 packages/airnode-protocol/deployments/lightlink/AirnodeRrpV0DryRun.json create mode 100644 packages/airnode-protocol/deployments/lightlink/RequesterAuthorizerWithAirnode.json create mode 100644 packages/airnode-protocol/deployments/lightlink/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json diff --git a/packages/airnode-protocol/deployments/lightlink/.chainId b/packages/airnode-protocol/deployments/lightlink/.chainId new file mode 100644 index 0000000000..d7e6ae9fa3 --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink/.chainId @@ -0,0 +1 @@ +1890 \ No newline at end of file diff --git a/packages/airnode-protocol/deployments/lightlink/AccessControlRegistry.json b/packages/airnode-protocol/deployments/lightlink/AccessControlRegistry.json new file mode 100644 index 0000000000..88ea5481c8 --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink/AccessControlRegistry.json @@ -0,0 +1,535 @@ +{ + "address": "0x92E5125adF385d86beDb950793526106143b6Df1", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "rootRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "InitializedManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "InitializedRole", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "name": "deriveRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "deriveRootRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "rootRole", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "initializeManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "name": "initializeRoleAndGrantToSender", + "outputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x33140713cbb1edcdd24b9bf5c4854b4219cc111bd4c52bcf54c68902adef330a", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xc97965EbD0f2123Cc31BEc63E18A8Ce9Ef6a1e7e", + "contractAddress": "0x0000000000000000000000000000000000000000", + "transactionIndex": 0, + "gasUsed": "1006525", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x5f5934b91078d7fbff473cd096ad6c9c6384dfe153c273f909f416de341b75e6", + "transactionHash": "0x33140713cbb1edcdd24b9bf5c4854b4219cc111bd4c52bcf54c68902adef330a", + "logs": [], + "blockNumber": 54178438, + "cumulativeGasUsed": "1006525", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "d8591a026515856ab7bc7dc284bf2fbe", + "metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"rootRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"manager\",\"type\":\"address\"}],\"name\":\"InitializedManager\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"adminRole\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"InitializedRole\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"adminRole\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"}],\"name\":\"deriveRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"manager\",\"type\":\"address\"}],\"name\":\"deriveRootRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"rootRole\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"manager\",\"type\":\"address\"}],\"name\":\"initializeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"adminRole\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"}],\"name\":\"initializeRoleAndGrantToSender\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Each user is called a \\\"manager\\\", and is the only member of their root role. Starting from this root role, they can create an arbitrary tree of roles and grant these to accounts. Each role has a description, and roles adminned by the same role cannot have the same description.\",\"kind\":\"dev\",\"methods\":{\"deriveRole(bytes32,string)\":{\"details\":\"This implies that roles adminned by the same role cannot have the same description\",\"params\":{\"adminRole\":\"Admin role\",\"description\":\"Human-readable description of the role\"},\"returns\":{\"role\":\"Role\"}},\"deriveRootRole(address)\":{\"params\":{\"manager\":\"Manager address\"},\"returns\":{\"rootRole\":\"Root role\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"initializeManager(address)\":{\"details\":\"Anyone can initialize a manager. An uninitialized manager attempting to initialize a role will be initialized automatically. Once a manager is initialized, subsequent initializations have no effect.\",\"params\":{\"manager\":\"Manager address to be initialized\"}},\"initializeRoleAndGrantToSender(bytes32,string)\":{\"details\":\"If the sender should not have the initialized role, they should explicitly renounce it after initializing it. Once a role is initialized, subsequent initializations have no effect other than granting the role to the sender. The sender must be a member of `adminRole`. `adminRole` value is not validated because the sender cannot have the `bytes32(0)` role. If the sender is an uninitialized manager that is initializing a role directly under their root role, manager initialization will happen automatically, which will grant the sender `adminRole` and allow them to initialize the role.\",\"params\":{\"adminRole\":\"Admin role to be assigned to the initialized role\",\"description\":\"Human-readable description of the initialized role\"},\"returns\":{\"role\":\"Initialized role\"}},\"multicall(bytes[])\":{\"details\":\"Receives and executes a batch of function calls on this contract.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Overriden to disallow managers to renounce their root roles. `role` and `account` are not validated because `AccessControl.renounceRole` will revert if either of them is zero.\",\"params\":{\"account\":\"Account to renounce the role\",\"role\":\"Role to be renounced\"}},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"title\":\"Contract that allows users to manage independent, tree-shaped access control tables\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deriveRole(bytes32,string)\":{\"notice\":\"Derives the role using its admin role and description\"},\"deriveRootRole(address)\":{\"notice\":\"Derives the root role of the manager\"},\"initializeManager(address)\":{\"notice\":\"Initializes the manager by initializing its root role and granting it to them\"},\"initializeRoleAndGrantToSender(bytes32,string)\":{\"notice\":\"Initializes a role by setting its admin role and grants it to the sender\"},\"renounceRole(bytes32,address)\":{\"notice\":\"Called by the account to renounce the role\"}},\"notice\":\"Multiple contracts can refer to this contract to check if their users have granted accounts specific roles. Therefore, it aims to keep all access control roles of its users in this single contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/access-control-registry/AccessControlRegistry.sol\":\"AccessControlRegistry\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/AccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControl.sol\\\";\\nimport \\\"../utils/Context.sol\\\";\\nimport \\\"../utils/Strings.sol\\\";\\nimport \\\"../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 * ```\\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 * ```\\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.\\n */\\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\\n struct RoleData {\\n mapping(address => bool) members;\\n bytes32 adminRole;\\n }\\n\\n mapping(bytes32 => 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 a standardized message including the required role.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n *\\n * _Available since v4.1._\\n */\\n modifier onlyRole(bytes32 role) {\\n _checkRole(role, _msgSender());\\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 override returns (bool) {\\n return _roles[role].members[account];\\n }\\n\\n /**\\n * @dev Revert with a standard message if `account` is missing `role`.\\n *\\n * The format of the revert reason is given by the following regular expression:\\n *\\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n */\\n function _checkRole(bytes32 role, address account) internal view {\\n if (!hasRole(role, account)) {\\n revert(\\n string(\\n abi.encodePacked(\\n \\\"AccessControl: account \\\",\\n Strings.toHexString(uint160(account), 20),\\n \\\" is missing role \\\",\\n Strings.toHexString(uint256(role), 32)\\n )\\n )\\n );\\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 override 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 function grantRole(bytes32 role, address account) public virtual override 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 function revokeRole(bytes32 role, address account) public virtual override 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 `account`.\\n */\\n function renounceRole(bytes32 role, address account) public virtual override {\\n require(account == _msgSender(), \\\"AccessControl: can only renounce roles for self\\\");\\n\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event. Note that unlike {grantRole}, this function doesn't perform any\\n * checks on the calling account.\\n *\\n * [WARNING]\\n * ====\\n * This function should only be called from the constructor when setting\\n * up the initial roles for the system.\\n *\\n * Using this function in any other way is effectively circumventing the admin\\n * system imposed by {AccessControl}.\\n * ====\\n *\\n * NOTE: This function is deprecated in favor of {_grantRole}.\\n */\\n function _setupRole(bytes32 role, address account) internal virtual {\\n _grantRole(role, account);\\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 Grants `role` to `account`.\\n *\\n * Internal function without access restriction.\\n */\\n function _grantRole(bytes32 role, address account) internal virtual {\\n if (!hasRole(role, account)) {\\n _roles[role].members[account] = true;\\n emit RoleGranted(role, account, _msgSender());\\n }\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * Internal function without access restriction.\\n */\\n function _revokeRole(bytes32 role, address account) internal virtual {\\n if (hasRole(role, account)) {\\n _roles[role].members[account] = false;\\n emit RoleRevoked(role, account, _msgSender());\\n }\\n }\\n}\\n\",\"keccak256\":\"0xb9a137b317dc4806805f2259686186c0c053c32d80fe9c15ecdbf2eb1cf52849\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\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 * _Available since v3.1._\\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 `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Multicall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Multicall.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @dev Provides a function to batch together multiple calls in a single external call.\\n *\\n * _Available since v4.1._\\n */\\nabstract contract Multicall {\\n /**\\n * @dev Receives and executes a batch of function calls on this contract.\\n */\\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n results[i] = Address.functionDelegateCall(address(this), data[i]);\\n }\\n return results;\\n }\\n}\\n\",\"keccak256\":\"0x768ccb0d556d2edde43cf5fc16860a936ce91eca96be0cf9e807ffe875f6f516\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./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 *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\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\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"contracts/access-control-registry/AccessControlRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"@openzeppelin/contracts/utils/Multicall.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/AccessControl.sol\\\";\\nimport \\\"./RoleDeriver.sol\\\";\\nimport \\\"./interfaces/IAccessControlRegistry.sol\\\";\\n\\n/// @title Contract that allows users to manage independent, tree-shaped access\\n/// control tables\\n/// @notice Multiple contracts can refer to this contract to check if their\\n/// users have granted accounts specific roles. Therefore, it aims to keep all\\n/// access control roles of its users in this single contract.\\n/// @dev Each user is called a \\\"manager\\\", and is the only member of their root\\n/// role. Starting from this root role, they can create an arbitrary tree of\\n/// roles and grant these to accounts. Each role has a description, and roles\\n/// adminned by the same role cannot have the same description.\\ncontract AccessControlRegistry is\\n Multicall,\\n AccessControl,\\n RoleDeriver,\\n IAccessControlRegistry\\n{\\n /// @notice Initializes the manager by initializing its root role and\\n /// granting it to them\\n /// @dev Anyone can initialize a manager. An uninitialized manager\\n /// attempting to initialize a role will be initialized automatically.\\n /// Once a manager is initialized, subsequent initializations have no\\n /// effect.\\n /// @param manager Manager address to be initialized\\n function initializeManager(address manager) public override {\\n require(manager != address(0), \\\"Manager address zero\\\");\\n bytes32 rootRole = deriveRootRole(manager);\\n if (!hasRole(rootRole, manager)) {\\n _grantRole(rootRole, manager);\\n emit InitializedManager(rootRole, manager);\\n }\\n }\\n\\n /// @notice Called by the account to renounce the role\\n /// @dev Overriden to disallow managers to renounce their root roles.\\n /// `role` and `account` are not validated because\\n /// `AccessControl.renounceRole` will revert if either of them is zero.\\n /// @param role Role to be renounced\\n /// @param account Account to renounce the role\\n function renounceRole(bytes32 role, address account)\\n public\\n override(AccessControl, IAccessControl)\\n {\\n require(\\n role != deriveRootRole(account),\\n \\\"role is root role of account\\\"\\n );\\n AccessControl.renounceRole(role, account);\\n }\\n\\n /// @notice Initializes a role by setting its admin role and grants it to\\n /// the sender\\n /// @dev If the sender should not have the initialized role, they should\\n /// explicitly renounce it after initializing it.\\n /// Once a role is initialized, subsequent initializations have no effect\\n /// other than granting the role to the sender.\\n /// The sender must be a member of `adminRole`. `adminRole` value is not\\n /// validated because the sender cannot have the `bytes32(0)` role.\\n /// If the sender is an uninitialized manager that is initializing a role\\n /// directly under their root role, manager initialization will happen\\n /// automatically, which will grant the sender `adminRole` and allow them\\n /// to initialize the role.\\n /// @param adminRole Admin role to be assigned to the initialized role\\n /// @param description Human-readable description of the initialized role\\n /// @return role Initialized role\\n function initializeRoleAndGrantToSender(\\n bytes32 adminRole,\\n string calldata description\\n ) external override returns (bytes32 role) {\\n require(bytes(description).length > 0, \\\"Role description empty\\\");\\n role = deriveRole(adminRole, description);\\n // AccessControl roles have `DEFAULT_ADMIN_ROLE` (i.e., `bytes32(0)`)\\n // as their `adminRole` by default. No account in AccessControlRegistry\\n // can possibly have that role, which means all initialized roles will\\n // have non-default admin roles, and vice versa.\\n if (getRoleAdmin(role) == DEFAULT_ADMIN_ROLE) {\\n if (adminRole == deriveRootRole(_msgSender())) {\\n initializeManager(_msgSender());\\n }\\n _setRoleAdmin(role, adminRole);\\n emit InitializedRole(role, adminRole, description, _msgSender());\\n }\\n grantRole(role, _msgSender());\\n }\\n\\n /// @notice Derives the root role of the manager\\n /// @param manager Manager address\\n /// @return rootRole Root role\\n function deriveRootRole(address manager)\\n public\\n pure\\n override\\n returns (bytes32 rootRole)\\n {\\n rootRole = _deriveRootRole(manager);\\n }\\n\\n /// @notice Derives the role using its admin role and description\\n /// @dev This implies that roles adminned by the same role cannot have the\\n /// same description\\n /// @param adminRole Admin role\\n /// @param description Human-readable description of the role\\n /// @return role Role\\n function deriveRole(bytes32 adminRole, string calldata description)\\n public\\n pure\\n override\\n returns (bytes32 role)\\n {\\n role = _deriveRole(adminRole, description);\\n }\\n}\\n\",\"keccak256\":\"0xc51bc818b977ba6e35c57da374da9727c1f103c54e1fb3725fbe419bfba4d39c\",\"license\":\"MIT\"},\"contracts/access-control-registry/RoleDeriver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @title Contract to be inherited by contracts that will derive\\n/// AccessControlRegistry roles\\n/// @notice If a contract interfaces with AccessControlRegistry and needs to\\n/// derive roles, it should inherit this contract instead of re-implementing\\n/// the logic\\ncontract RoleDeriver {\\n /// @notice Derives the root role of the manager\\n /// @param manager Manager address\\n /// @return rootRole Root role\\n function _deriveRootRole(address manager)\\n internal\\n pure\\n returns (bytes32 rootRole)\\n {\\n rootRole = keccak256(abi.encodePacked(manager));\\n }\\n\\n /// @notice Derives the role using its admin role and description\\n /// @dev This implies that roles adminned by the same role cannot have the\\n /// same description\\n /// @param adminRole Admin role\\n /// @param description Human-readable description of the role\\n /// @return role Role\\n function _deriveRole(bytes32 adminRole, string memory description)\\n internal\\n pure\\n returns (bytes32 role)\\n {\\n role = _deriveRole(adminRole, keccak256(abi.encodePacked(description)));\\n }\\n\\n /// @notice Derives the role using its admin role and description hash\\n /// @dev This implies that roles adminned by the same role cannot have the\\n /// same description\\n /// @param adminRole Admin role\\n /// @param descriptionHash Hash of the human-readable description of the\\n /// role\\n /// @return role Role\\n function _deriveRole(bytes32 adminRole, bytes32 descriptionHash)\\n internal\\n pure\\n returns (bytes32 role)\\n {\\n role = keccak256(abi.encodePacked(adminRole, descriptionHash));\\n }\\n}\\n\",\"keccak256\":\"0x20fe9d6cce9a1e4fe0b5bd8868fabbe6ee9db7fa8154bcf6316005307d63ee04\",\"license\":\"MIT\"},\"contracts/access-control-registry/interfaces/IAccessControlRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/IAccessControl.sol\\\";\\n\\ninterface IAccessControlRegistry is IAccessControl {\\n event InitializedManager(bytes32 indexed rootRole, address indexed manager);\\n\\n event InitializedRole(\\n bytes32 indexed role,\\n bytes32 indexed adminRole,\\n string description,\\n address sender\\n );\\n\\n function initializeManager(address manager) external;\\n\\n function initializeRoleAndGrantToSender(\\n bytes32 adminRole,\\n string calldata description\\n ) external returns (bytes32 role);\\n\\n function deriveRootRole(address manager)\\n external\\n pure\\n returns (bytes32 rootRole);\\n\\n function deriveRole(bytes32 adminRole, string calldata description)\\n external\\n pure\\n returns (bytes32 role);\\n}\\n\",\"keccak256\":\"0x51b6c37b03f81667920dac10d53efc75e403c11348e71311b39a25c9b1cfdf76\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50611145806100206000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063805d43fc11610081578063ac9650d81161005b578063ac9650d8146101d2578063b530b5e0146101f2578063d547741f1461020557600080fd5b8063805d43fc1461018057806391d1485414610193578063a217fddf146101ca57600080fd5b806336568abe116100b257806336568abe1461014757806373e983621461015a5780637f7120fe1461016d57600080fd5b806301ffc9a7146100d9578063248a9ca3146101015780632f2ff15d14610132575b600080fd5b6100ec6100e7366004610c90565b610218565b60405190151581526020015b60405180910390f35b61012461010f366004610cd2565b60009081526020819052604090206001015490565b6040519081526020016100f8565b610145610140366004610d07565b6102b1565b005b610145610155366004610d07565b6102dc565b610124610168366004610d33565b610347565b61014561017b366004610daf565b61042e565b61012461018e366004610daf565b6104fe565b6100ec6101a1366004610d07565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b610124600081565b6101e56101e0366004610dca565b61053e565b6040516100f89190610e9b565b610124610200366004610d33565b610633565b610145610213366004610d07565b61067d565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806102ab57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000828152602081905260409020600101546102cd81336106a3565b6102d78383610721565b505050565b6102e5816104fe565b8214156103395760405162461bcd60e51b815260206004820152601c60248201527f726f6c6520697320726f6f7420726f6c65206f66206163636f756e740000000060448201526064015b60405180910390fd5b61034382826107bf565b5050565b6000816103965760405162461bcd60e51b815260206004820152601660248201527f526f6c65206465736372697074696f6e20656d707479000000000000000000006044820152606401610330565b6103a1848484610633565b600081815260208190526040812060010154919250141561041d576103c5336104fe565b8414156103d5576103d53361042e565b6103df8185610847565b83817f532ead3ec09896bef1351791fbaad86ac03f3204090a8e7f173f41414b1fdac085853360405161041493929190610efd565b60405180910390a35b61042781336102b1565b9392505050565b6001600160a01b0381166104845760405162461bcd60e51b815260206004820152601460248201527f4d616e616765722061646472657373207a65726f0000000000000000000000006044820152606401610330565b600061048f826104fe565b6000818152602081815260408083206001600160a01b038716845290915290205490915060ff16610343576104c48183610721565b6040516001600160a01b0383169082907f888b171f3b02386c0e4d8c85108dcb8d0ecdad2f274ddc7ce3914282538bdd8890600090a35050565b60408051606083901b6bffffffffffffffffffffffff191660208083019190915282516014818403018152603490920190925280519101206000906102ab565b60608167ffffffffffffffff81111561055957610559610f3f565b60405190808252806020026020018201604052801561058c57816020015b60608152602001906001900390816105775790505b50905060005b8281101561062c576105fc308585848181106105b0576105b0610f55565b90506020028101906105c29190610f6b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061089292505050565b82828151811061060e5761060e610f55565b6020026020010181905250808061062490610fcf565b915050610592565b5092915050565b60006106758484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506108b792505050565b949350505050565b60008281526020819052604090206001015461069981336106a3565b6102d7838361090c565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610343576106df816001600160a01b0316601461098b565b6106ea83602061098b565b6040516020016106fb929190610fea565b60408051601f198184030181529082905262461bcd60e51b82526103309160040161106b565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610343576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561077b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b038116331461083d5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610330565b610343828261090c565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b606061042783836040518060600160405280602781526020016110e960279139610b6c565b600061042783836040516020016108ce919061107e565b60408051601f198184030181528282528051602091820120838201949094528282019390935280518083038201815260609092019052805191012090565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610343576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6060600061099a83600261109a565b6109a59060026110b9565b67ffffffffffffffff8111156109bd576109bd610f3f565b6040519080825280601f01601f1916602001820160405280156109e7576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110610a1e57610a1e610f55565b60200101906001600160f81b031916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110610a6957610a69610f55565b60200101906001600160f81b031916908160001a9053506000610a8d84600261109a565b610a989060016110b9565b90505b6001811115610b1d577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110610ad957610ad9610f55565b1a60f81b828281518110610aef57610aef610f55565b60200101906001600160f81b031916908160001a90535060049490941c93610b16816110d1565b9050610a9b565b5083156104275760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610330565b6060833b610be25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610330565b600080856001600160a01b031685604051610bfd919061107e565b600060405180830381855af49150503d8060008114610c38576040519150601f19603f3d011682016040523d82523d6000602084013e610c3d565b606091505b5091509150610c4d828286610c57565b9695505050505050565b60608315610c66575081610427565b825115610c765782518084602001fd5b8160405162461bcd60e51b8152600401610330919061106b565b600060208284031215610ca257600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461042757600080fd5b600060208284031215610ce457600080fd5b5035919050565b80356001600160a01b0381168114610d0257600080fd5b919050565b60008060408385031215610d1a57600080fd5b82359150610d2a60208401610ceb565b90509250929050565b600080600060408486031215610d4857600080fd5b83359250602084013567ffffffffffffffff80821115610d6757600080fd5b818601915086601f830112610d7b57600080fd5b813581811115610d8a57600080fd5b876020828501011115610d9c57600080fd5b6020830194508093505050509250925092565b600060208284031215610dc157600080fd5b61042782610ceb565b60008060208385031215610ddd57600080fd5b823567ffffffffffffffff80821115610df557600080fd5b818501915085601f830112610e0957600080fd5b813581811115610e1857600080fd5b8660208260051b8501011115610e2d57600080fd5b60209290920196919550909350505050565b60005b83811015610e5a578181015183820152602001610e42565b83811115610e69576000848401525b50505050565b60008151808452610e87816020860160208601610e3f565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ef057603f19888603018452610ede858351610e6f565b94509285019290850190600101610ec2565b5092979650505050505050565b604081528260408201528284606083013760006060848301015260006060601f19601f86011683010190506001600160a01b0383166020830152949350505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112610f8257600080fd5b83018035915067ffffffffffffffff821115610f9d57600080fd5b602001915036819003821315610fb257600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415610fe357610fe3610fb9565b5060010190565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611022816017850160208801610e3f565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161105f816028840160208801610e3f565b01602801949350505050565b6020815260006104276020830184610e6f565b60008251611090818460208701610e3f565b9190910192915050565b60008160001904831182151516156110b4576110b4610fb9565b500290565b600082198211156110cc576110cc610fb9565b500190565b6000816110e0576110e0610fb9565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207cc002eec550ca333e5647aeee1bec01baf44cbf2540ae519fcdad161591c81864736f6c63430008090033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100d45760003560e01c8063805d43fc11610081578063ac9650d81161005b578063ac9650d8146101d2578063b530b5e0146101f2578063d547741f1461020557600080fd5b8063805d43fc1461018057806391d1485414610193578063a217fddf146101ca57600080fd5b806336568abe116100b257806336568abe1461014757806373e983621461015a5780637f7120fe1461016d57600080fd5b806301ffc9a7146100d9578063248a9ca3146101015780632f2ff15d14610132575b600080fd5b6100ec6100e7366004610c90565b610218565b60405190151581526020015b60405180910390f35b61012461010f366004610cd2565b60009081526020819052604090206001015490565b6040519081526020016100f8565b610145610140366004610d07565b6102b1565b005b610145610155366004610d07565b6102dc565b610124610168366004610d33565b610347565b61014561017b366004610daf565b61042e565b61012461018e366004610daf565b6104fe565b6100ec6101a1366004610d07565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b610124600081565b6101e56101e0366004610dca565b61053e565b6040516100f89190610e9b565b610124610200366004610d33565b610633565b610145610213366004610d07565b61067d565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806102ab57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000828152602081905260409020600101546102cd81336106a3565b6102d78383610721565b505050565b6102e5816104fe565b8214156103395760405162461bcd60e51b815260206004820152601c60248201527f726f6c6520697320726f6f7420726f6c65206f66206163636f756e740000000060448201526064015b60405180910390fd5b61034382826107bf565b5050565b6000816103965760405162461bcd60e51b815260206004820152601660248201527f526f6c65206465736372697074696f6e20656d707479000000000000000000006044820152606401610330565b6103a1848484610633565b600081815260208190526040812060010154919250141561041d576103c5336104fe565b8414156103d5576103d53361042e565b6103df8185610847565b83817f532ead3ec09896bef1351791fbaad86ac03f3204090a8e7f173f41414b1fdac085853360405161041493929190610efd565b60405180910390a35b61042781336102b1565b9392505050565b6001600160a01b0381166104845760405162461bcd60e51b815260206004820152601460248201527f4d616e616765722061646472657373207a65726f0000000000000000000000006044820152606401610330565b600061048f826104fe565b6000818152602081815260408083206001600160a01b038716845290915290205490915060ff16610343576104c48183610721565b6040516001600160a01b0383169082907f888b171f3b02386c0e4d8c85108dcb8d0ecdad2f274ddc7ce3914282538bdd8890600090a35050565b60408051606083901b6bffffffffffffffffffffffff191660208083019190915282516014818403018152603490920190925280519101206000906102ab565b60608167ffffffffffffffff81111561055957610559610f3f565b60405190808252806020026020018201604052801561058c57816020015b60608152602001906001900390816105775790505b50905060005b8281101561062c576105fc308585848181106105b0576105b0610f55565b90506020028101906105c29190610f6b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061089292505050565b82828151811061060e5761060e610f55565b6020026020010181905250808061062490610fcf565b915050610592565b5092915050565b60006106758484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506108b792505050565b949350505050565b60008281526020819052604090206001015461069981336106a3565b6102d7838361090c565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610343576106df816001600160a01b0316601461098b565b6106ea83602061098b565b6040516020016106fb929190610fea565b60408051601f198184030181529082905262461bcd60e51b82526103309160040161106b565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610343576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561077b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b038116331461083d5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610330565b610343828261090c565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b606061042783836040518060600160405280602781526020016110e960279139610b6c565b600061042783836040516020016108ce919061107e565b60408051601f198184030181528282528051602091820120838201949094528282019390935280518083038201815260609092019052805191012090565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610343576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6060600061099a83600261109a565b6109a59060026110b9565b67ffffffffffffffff8111156109bd576109bd610f3f565b6040519080825280601f01601f1916602001820160405280156109e7576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110610a1e57610a1e610f55565b60200101906001600160f81b031916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110610a6957610a69610f55565b60200101906001600160f81b031916908160001a9053506000610a8d84600261109a565b610a989060016110b9565b90505b6001811115610b1d577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110610ad957610ad9610f55565b1a60f81b828281518110610aef57610aef610f55565b60200101906001600160f81b031916908160001a90535060049490941c93610b16816110d1565b9050610a9b565b5083156104275760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610330565b6060833b610be25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610330565b600080856001600160a01b031685604051610bfd919061107e565b600060405180830381855af49150503d8060008114610c38576040519150601f19603f3d011682016040523d82523d6000602084013e610c3d565b606091505b5091509150610c4d828286610c57565b9695505050505050565b60608315610c66575081610427565b825115610c765782518084602001fd5b8160405162461bcd60e51b8152600401610330919061106b565b600060208284031215610ca257600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461042757600080fd5b600060208284031215610ce457600080fd5b5035919050565b80356001600160a01b0381168114610d0257600080fd5b919050565b60008060408385031215610d1a57600080fd5b82359150610d2a60208401610ceb565b90509250929050565b600080600060408486031215610d4857600080fd5b83359250602084013567ffffffffffffffff80821115610d6757600080fd5b818601915086601f830112610d7b57600080fd5b813581811115610d8a57600080fd5b876020828501011115610d9c57600080fd5b6020830194508093505050509250925092565b600060208284031215610dc157600080fd5b61042782610ceb565b60008060208385031215610ddd57600080fd5b823567ffffffffffffffff80821115610df557600080fd5b818501915085601f830112610e0957600080fd5b813581811115610e1857600080fd5b8660208260051b8501011115610e2d57600080fd5b60209290920196919550909350505050565b60005b83811015610e5a578181015183820152602001610e42565b83811115610e69576000848401525b50505050565b60008151808452610e87816020860160208601610e3f565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ef057603f19888603018452610ede858351610e6f565b94509285019290850190600101610ec2565b5092979650505050505050565b604081528260408201528284606083013760006060848301015260006060601f19601f86011683010190506001600160a01b0383166020830152949350505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112610f8257600080fd5b83018035915067ffffffffffffffff821115610f9d57600080fd5b602001915036819003821315610fb257600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415610fe357610fe3610fb9565b5060010190565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611022816017850160208801610e3f565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161105f816028840160208801610e3f565b01602801949350505050565b6020815260006104276020830184610e6f565b60008251611090818460208701610e3f565b9190910192915050565b60008160001904831182151516156110b4576110b4610fb9565b500290565b600082198211156110cc576110cc610fb9565b500190565b6000816110e0576110e0610fb9565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207cc002eec550ca333e5647aeee1bec01baf44cbf2540ae519fcdad161591c81864736f6c63430008090033", + "devdoc": { + "details": "Each user is called a \"manager\", and is the only member of their root role. Starting from this root role, they can create an arbitrary tree of roles and grant these to accounts. Each role has a description, and roles adminned by the same role cannot have the same description.", + "kind": "dev", + "methods": { + "deriveRole(bytes32,string)": { + "details": "This implies that roles adminned by the same role cannot have the same description", + "params": { + "adminRole": "Admin role", + "description": "Human-readable description of the role" + }, + "returns": { + "role": "Role" + } + }, + "deriveRootRole(address)": { + "params": { + "manager": "Manager address" + }, + "returns": { + "rootRole": "Root role" + } + }, + "getRoleAdmin(bytes32)": { + "details": "Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}." + }, + "grantRole(bytes32,address)": { + "details": "Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role." + }, + "hasRole(bytes32,address)": { + "details": "Returns `true` if `account` has been granted `role`." + }, + "initializeManager(address)": { + "details": "Anyone can initialize a manager. An uninitialized manager attempting to initialize a role will be initialized automatically. Once a manager is initialized, subsequent initializations have no effect.", + "params": { + "manager": "Manager address to be initialized" + } + }, + "initializeRoleAndGrantToSender(bytes32,string)": { + "details": "If the sender should not have the initialized role, they should explicitly renounce it after initializing it. Once a role is initialized, subsequent initializations have no effect other than granting the role to the sender. The sender must be a member of `adminRole`. `adminRole` value is not validated because the sender cannot have the `bytes32(0)` role. If the sender is an uninitialized manager that is initializing a role directly under their root role, manager initialization will happen automatically, which will grant the sender `adminRole` and allow them to initialize the role.", + "params": { + "adminRole": "Admin role to be assigned to the initialized role", + "description": "Human-readable description of the initialized role" + }, + "returns": { + "role": "Initialized role" + } + }, + "multicall(bytes[])": { + "details": "Receives and executes a batch of function calls on this contract." + }, + "renounceRole(bytes32,address)": { + "details": "Overriden to disallow managers to renounce their root roles. `role` and `account` are not validated because `AccessControl.renounceRole` will revert if either of them is zero.", + "params": { + "account": "Account to renounce the role", + "role": "Role to be renounced" + } + }, + "revokeRole(bytes32,address)": { + "details": "Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role." + }, + "supportsInterface(bytes4)": { + "details": "See {IERC165-supportsInterface}." + } + }, + "title": "Contract that allows users to manage independent, tree-shaped access control tables", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "deriveRole(bytes32,string)": { + "notice": "Derives the role using its admin role and description" + }, + "deriveRootRole(address)": { + "notice": "Derives the root role of the manager" + }, + "initializeManager(address)": { + "notice": "Initializes the manager by initializing its root role and granting it to them" + }, + "initializeRoleAndGrantToSender(bytes32,string)": { + "notice": "Initializes a role by setting its admin role and grants it to the sender" + }, + "renounceRole(bytes32,address)": { + "notice": "Called by the account to renounce the role" + } + }, + "notice": "Multiple contracts can refer to this contract to check if their users have granted accounts specific roles. Therefore, it aims to keep all access control roles of its users in this single contract.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 24, + "contract": "contracts/access-control-registry/AccessControlRegistry.sol:AccessControlRegistry", + "label": "_roles", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_struct(RoleData)19_storage)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_bytes32,t_struct(RoleData)19_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct AccessControl.RoleData)", + "numberOfBytes": "32", + "value": "t_struct(RoleData)19_storage" + }, + "t_struct(RoleData)19_storage": { + "encoding": "inplace", + "label": "struct AccessControl.RoleData", + "members": [ + { + "astId": 16, + "contract": "contracts/access-control-registry/AccessControlRegistry.sol:AccessControlRegistry", + "label": "members", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 18, + "contract": "contracts/access-control-registry/AccessControlRegistry.sol:AccessControlRegistry", + "label": "adminRole", + "offset": 0, + "slot": "1", + "type": "t_bytes32" + } + ], + "numberOfBytes": "64" + } + } + } +} diff --git a/packages/airnode-protocol/deployments/lightlink/AirnodeRrpV0.json b/packages/airnode-protocol/deployments/lightlink/AirnodeRrpV0.json new file mode 100644 index 0000000000..61e98456be --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink/AirnodeRrpV0.json @@ -0,0 +1,1184 @@ +{ + "address": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "templateId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "CreatedTemplate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "string", + "name": "errorMessage", + "type": "string" + } + ], + "name": "FailedRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "FulfilledRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "withdrawalRequestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "FulfilledWithdrawal", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "requesterRequestCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "MadeFullRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "requesterRequestCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "templateId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "MadeTemplateRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "withdrawalRequestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + } + ], + "name": "RequestedWithdrawal", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "sponsorshipStatus", + "type": "bool" + } + ], + "name": "SetSponsorshipStatus", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "authorizers", + "type": "address[]" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + } + ], + "name": "checkAuthorizationStatus", + "outputs": [ + { + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "authorizers", + "type": "address[]" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32[]", + "name": "requestIds", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "endpointIds", + "type": "bytes32[]" + }, + { + "internalType": "address[]", + "name": "sponsors", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "requesters", + "type": "address[]" + } + ], + "name": "checkAuthorizationStatuses", + "outputs": [ + { + "internalType": "bool[]", + "name": "statuses", + "type": "bool[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "createTemplate", + "outputs": [ + { + "internalType": "bytes32", + "name": "templateId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "internalType": "string", + "name": "errorMessage", + "type": "string" + } + ], + "name": "fail", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "fulfill", + "outputs": [ + { + "internalType": "bool", + "name": "callSuccess", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRequestId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "address", + "name": "sponsor", + "type": "address" + } + ], + "name": "fulfillWithdrawal", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[]", + "name": "templateIds", + "type": "bytes32[]" + } + ], + "name": "getTemplates", + "outputs": [ + { + "internalType": "address[]", + "name": "airnodes", + "type": "address[]" + }, + { + "internalType": "bytes32[]", + "name": "endpointIds", + "type": "bytes32[]" + }, + { + "internalType": "bytes[]", + "name": "parameters", + "type": "bytes[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + }, + { + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "makeFullRequest", + "outputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "templateId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + }, + { + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "name": "makeTemplateRequest", + "outputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + } + ], + "name": "requestIsAwaitingFulfillment", + "outputs": [ + { + "internalType": "bool", + "name": "isAwaitingFulfillment", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "address", + "name": "sponsorWallet", + "type": "address" + } + ], + "name": "requestWithdrawal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "requesterToRequestCountPlusOne", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bool", + "name": "sponsorshipStatus", + "type": "bool" + } + ], + "name": "setSponsorshipStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "sponsorToRequesterToSponsorshipStatus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "sponsorToWithdrawalRequestCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "templates", + "outputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "parameters", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x24c9f2030d7859d3392617001998ea68b997da0866bc029db6f17de0fbb26b56", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xc97965EbD0f2123Cc31BEc63E18A8Ce9Ef6a1e7e", + "contractAddress": "0x0000000000000000000000000000000000000000", + "transactionIndex": 0, + "gasUsed": "2228742", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x6b298c9d5362569069f9eef74fde75c0c47d83a1a34b682f3c0892cd52e3ea38", + "transactionHash": "0x24c9f2030d7859d3392617001998ea68b997da0866bc029db6f17de0fbb26b56", + "logs": [], + "blockNumber": 54178461, + "cumulativeGasUsed": "2228742", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "d8591a026515856ab7bc7dc284bf2fbe", + "metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"templateId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"CreatedTemplate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"errorMessage\",\"type\":\"string\"}],\"name\":\"FailedRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FulfilledRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"withdrawalRequestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FulfilledWithdrawal\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requesterRequestCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"MadeFullRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requesterRequestCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"templateId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"MadeTemplateRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"withdrawalRequestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"}],\"name\":\"RequestedWithdrawal\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sponsorshipStatus\",\"type\":\"bool\"}],\"name\":\"SetSponsorshipStatus\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"authorizers\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"name\":\"checkAuthorizationStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"authorizers\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"requestIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"endpointIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"sponsors\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"requesters\",\"type\":\"address[]\"}],\"name\":\"checkAuthorizationStatuses\",\"outputs\":[{\"internalType\":\"bool[]\",\"name\":\"statuses\",\"type\":\"bool[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"createTemplate\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"templateId\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"errorMessage\",\"type\":\"string\"}],\"name\":\"fail\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"callSuccess\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRequestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"}],\"name\":\"fulfillWithdrawal\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"templateIds\",\"type\":\"bytes32[]\"}],\"name\":\"getTemplates\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"airnodes\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"endpointIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes[]\",\"name\":\"parameters\",\"type\":\"bytes[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"makeFullRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"templateId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"name\":\"makeTemplateRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"requestIsAwaitingFulfillment\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isAwaitingFulfillment\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"sponsorWallet\",\"type\":\"address\"}],\"name\":\"requestWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"requesterToRequestCountPlusOne\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"sponsorshipStatus\",\"type\":\"bool\"}],\"name\":\"setSponsorshipStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"sponsorToRequesterToSponsorshipStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"sponsorToWithdrawalRequestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"templates\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"parameters\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"checkAuthorizationStatus(address[],address,bytes32,bytes32,address,address)\":{\"details\":\"This method is meant to be called off-chain, statically by the Airnode to decide if it should respond to a request. The requester can also call it, yet this function returning true should not be taken as a guarantee of the subsequent request being fulfilled. It is enough for only one of the authorizer contracts to return true for the request to be authorized.\",\"params\":{\"airnode\":\"Airnode address\",\"authorizers\":\"Authorizer contract addresses\",\"endpointId\":\"Endpoint ID\",\"requestId\":\"Request ID\",\"requester\":\"Requester address\",\"sponsor\":\"Sponsor address\"},\"returns\":{\"status\":\"Authorization status of the request\"}},\"checkAuthorizationStatuses(address[],address,bytes32[],bytes32[],address[],address[])\":{\"params\":{\"airnode\":\"Airnode address\",\"authorizers\":\"Authorizer contract addresses\",\"endpointIds\":\"Endpoint IDs\",\"requestIds\":\"Request IDs\",\"requesters\":\"Requester addresses\",\"sponsors\":\"Sponsor addresses\"},\"returns\":{\"statuses\":\"Authorization statuses of the request\"}},\"createTemplate(address,bytes32,bytes)\":{\"details\":\"A specific set of request parameters will always have the same template ID. This means a few things: (1) You can compute the expected ID of a template before creating it, (2) Creating a new template with the same parameters will overwrite the old one and return the same ID, (3) After you query a template with its ID, you can verify its integrity by applying the hash and comparing the result with the ID.\",\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID (allowed to be `bytes32(0)`)\",\"parameters\":\"Static request parameters (i.e., parameters that will not change between requests, unlike the dynamic parameters determined at request-time)\"},\"returns\":{\"templateId\":\"Request template ID\"}},\"fail(bytes32,address,address,bytes4,string)\":{\"details\":\"Airnode should fall back to this if a request cannot be fulfilled because static call to `fulfill()` returns `false` for `callSuccess`\",\"params\":{\"airnode\":\"Airnode address\",\"errorMessage\":\"A message that explains why the request has failed\",\"fulfillAddress\":\"Address that will be called to fulfill\",\"fulfillFunctionId\":\"Signature of the function that will be called to fulfill\",\"requestId\":\"Request ID\"}},\"fulfill(bytes32,address,address,bytes4,bytes,bytes)\":{\"details\":\"The data is ABI-encoded as a `bytes` type, with its format depending on the request specifications. This will not revert depending on the external call. However, it will return `false` if the external call reverts or if there is no function with a matching signature at `fulfillAddress`. On the other hand, it will return `true` if the external call returns successfully or if there is no contract deployed at `fulfillAddress`. If `callSuccess` is `false`, `callData` can be decoded to retrieve the revert string. This function emits its event after an untrusted low-level call, meaning that the order of these events within the transaction should not be taken seriously, yet the content will be sound.\",\"params\":{\"airnode\":\"Airnode address\",\"data\":\"Fulfillment data\",\"fulfillAddress\":\"Address that will be called to fulfill\",\"fulfillFunctionId\":\"Signature of the function that will be called to fulfill\",\"requestId\":\"Request ID\"},\"returns\":{\"callData\":\"Data returned by the fulfillment call (if there is any)\",\"callSuccess\":\"If the fulfillment call succeeded\"}},\"fulfillWithdrawal(bytes32,address,address)\":{\"details\":\"The Airnode sends the funds to the sponsor through this method to emit an event that indicates that the withdrawal request has been fulfilled\",\"params\":{\"airnode\":\"Airnode address\",\"sponsor\":\"Sponsor address\",\"withdrawalRequestId\":\"Withdrawal request ID\"}},\"getTemplates(bytes32[])\":{\"details\":\"Does not revert if the templates being indexed do not exist\",\"params\":{\"templateIds\":\"Request template IDs\"},\"returns\":{\"airnodes\":\"Array of Airnode addresses\",\"endpointIds\":\"Array of endpoint IDs\",\"parameters\":\"Array of request parameters\"}},\"makeFullRequest(address,bytes32,address,address,address,bytes4,bytes)\":{\"details\":\"`fulfillAddress` is not allowed to be the address of this contract. This is not actually needed to protect users that use the protocol as intended, but it is done for good measure.\",\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID (allowed to be `bytes32(0)`)\",\"fulfillAddress\":\"Address that will be called to fulfill\",\"fulfillFunctionId\":\"Signature of the function that will be called to fulfill\",\"parameters\":\"All request parameters\",\"sponsor\":\"Sponsor address\",\"sponsorWallet\":\"Sponsor wallet that is requested to fulfill the request\"},\"returns\":{\"requestId\":\"Request ID\"}},\"makeTemplateRequest(bytes32,address,address,address,bytes4,bytes)\":{\"details\":\"`fulfillAddress` is not allowed to be the address of this contract. This is not actually needed to protect users that use the protocol as intended, but it is done for good measure.\",\"params\":{\"fulfillAddress\":\"Address that will be called to fulfill\",\"fulfillFunctionId\":\"Signature of the function that will be called to fulfill\",\"parameters\":\"Parameters provided by the requester in addition to the parameters in the template\",\"sponsor\":\"Sponsor address\",\"sponsorWallet\":\"Sponsor wallet that is requested to fulfill the request\",\"templateId\":\"Template ID\"},\"returns\":{\"requestId\":\"Request ID\"}},\"requestIsAwaitingFulfillment(bytes32)\":{\"details\":\"If a requester has made a request, received a request ID but did not hear back, it can call this method to check if the Airnode has called back `fail()` instead.\",\"params\":{\"requestId\":\"Request ID\"},\"returns\":{\"isAwaitingFulfillment\":\"If the request is awaiting fulfillment (i.e., `true` if `fulfill()` or `fail()` is not called back yet, `false` otherwise)\"}},\"requestWithdrawal(address,address)\":{\"details\":\"We do not need to use the withdrawal request parameters in the request ID hash to validate them at the node-side because all of the parameters are used during fulfillment and will get validated on-chain. The first withdrawal request a sponsor will make will cost slightly higher gas than the rest due to how the request counter is implemented.\",\"params\":{\"airnode\":\"Airnode address\",\"sponsorWallet\":\"Sponsor wallet that the withdrawal is requested from\"}},\"setSponsorshipStatus(address,bool)\":{\"details\":\"This is not Airnode-specific, i.e., the sponsor allows the requester's requests to be fulfilled through its sponsor wallets across all Airnodes\",\"params\":{\"requester\":\"Requester address\",\"sponsorshipStatus\":\"Sponsorship status\"}}},\"stateVariables\":{\"requestIdToFulfillmentParameters\":{\"details\":\"Hash of expected fulfillment parameters are kept to verify that the fulfillment will be done with the correct parameters. This value is also used to check if the fulfillment for the particular request is expected, i.e., if there are recorded fulfillment parameters.\"},\"requesterToRequestCountPlusOne\":{\"details\":\"Can be used to calculate the ID of the next request the requester will make\"}},\"title\":\"Contract that implements the Airnode request\\u2013response protocol (RRP)\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"checkAuthorizationStatus(address[],address,bytes32,bytes32,address,address)\":{\"notice\":\"Uses the authorizer contracts of an Airnode to decide if a request is authorized. Once an Airnode receives a request, it calls this method to determine if it should respond. Similarly, third parties can use this method to determine if a particular request would be authorized.\"},\"checkAuthorizationStatuses(address[],address,bytes32[],bytes32[],address[],address[])\":{\"notice\":\"A convenience function to make multiple authorization status checks with a single call\"},\"createTemplate(address,bytes32,bytes)\":{\"notice\":\"Creates a request template with the given parameters, addressable by the ID it returns\"},\"fail(bytes32,address,address,bytes4,string)\":{\"notice\":\"Called by Airnode if the request cannot be fulfilled\"},\"fulfill(bytes32,address,address,bytes4,bytes,bytes)\":{\"notice\":\"Called by Airnode to fulfill the request (template or full)\"},\"fulfillWithdrawal(bytes32,address,address)\":{\"notice\":\"Called by the Airnode using the sponsor wallet to fulfill the withdrawal request made by the sponsor\"},\"getTemplates(bytes32[])\":{\"notice\":\"A convenience method to retrieve multiple templates with a single call\"},\"makeFullRequest(address,bytes32,address,address,address,bytes4,bytes)\":{\"notice\":\"Called by the requester to make a full request, which provides all of its parameters as arguments and does not refer to a template\"},\"makeTemplateRequest(bytes32,address,address,address,bytes4,bytes)\":{\"notice\":\"Called by the requester to make a request that refers to a template for the Airnode address, endpoint ID and parameters\"},\"requestIsAwaitingFulfillment(bytes32)\":{\"notice\":\"Called to check if the request with the ID is made but not fulfilled/failed yet\"},\"requestWithdrawal(address,address)\":{\"notice\":\"Called by a sponsor to create a request for the Airnode to send the funds kept in the respective sponsor wallet to the sponsor\"},\"requesterToRequestCountPlusOne(address)\":{\"notice\":\"Called to get the request count of the requester plus one\"},\"setSponsorshipStatus(address,bool)\":{\"notice\":\"Called by the sponsor to set the sponsorship status of a requester, i.e., allow or disallow a requester to make requests that will be fulfilled by the sponsor wallet\"},\"sponsorToRequesterToSponsorshipStatus(address,address)\":{\"notice\":\"Called to get the sponsorship status for a sponsor\\u2013requester pair\"},\"sponsorToWithdrawalRequestCount(address)\":{\"notice\":\"Called to get the withdrawal request count of the sponsor\"},\"templates(bytes32)\":{\"notice\":\"Called to get a template\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/rrp/AirnodeRrpV0.sol\":\"AirnodeRrpV0\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s;\\n uint8 v;\\n assembly {\\n s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\\n v := add(shr(255, vs), 27)\\n }\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xe9e291de7ffe06e66503c6700b1bb84ff6e0989cbb974653628d8994e7c97f03\",\"license\":\"MIT\"},\"contracts/authorizers/interfaces/IAuthorizerV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IAuthorizerV0 {\\n function isAuthorizedV0(\\n bytes32 requestId,\\n address airnode,\\n bytes32 endpointId,\\n address sponsor,\\n address requester\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xa38872f5dead4dfc0c8075c245c10197df1ace09415f2e0d5b46bc8511cc3f6d\",\"license\":\"MIT\"},\"contracts/rrp/AirnodeRrpV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"./AuthorizationUtilsV0.sol\\\";\\nimport \\\"./TemplateUtilsV0.sol\\\";\\nimport \\\"./WithdrawalUtilsV0.sol\\\";\\nimport \\\"./interfaces/IAirnodeRrpV0.sol\\\";\\n\\n/// @title Contract that implements the Airnode request\\u2013response protocol (RRP)\\ncontract AirnodeRrpV0 is\\n AuthorizationUtilsV0,\\n TemplateUtilsV0,\\n WithdrawalUtilsV0,\\n IAirnodeRrpV0\\n{\\n using ECDSA for bytes32;\\n\\n /// @notice Called to get the sponsorship status for a sponsor\\u2013requester\\n /// pair\\n mapping(address => mapping(address => bool))\\n public\\n override sponsorToRequesterToSponsorshipStatus;\\n\\n /// @notice Called to get the request count of the requester plus one\\n /// @dev Can be used to calculate the ID of the next request the requester\\n /// will make\\n mapping(address => uint256) public override requesterToRequestCountPlusOne;\\n\\n /// @dev Hash of expected fulfillment parameters are kept to verify that\\n /// the fulfillment will be done with the correct parameters. This value is\\n /// also used to check if the fulfillment for the particular request is\\n /// expected, i.e., if there are recorded fulfillment parameters.\\n mapping(bytes32 => bytes32) private requestIdToFulfillmentParameters;\\n\\n /// @notice Called by the sponsor to set the sponsorship status of a\\n /// requester, i.e., allow or disallow a requester to make requests that\\n /// will be fulfilled by the sponsor wallet\\n /// @dev This is not Airnode-specific, i.e., the sponsor allows the\\n /// requester's requests to be fulfilled through its sponsor wallets across\\n /// all Airnodes\\n /// @param requester Requester address\\n /// @param sponsorshipStatus Sponsorship status\\n function setSponsorshipStatus(address requester, bool sponsorshipStatus)\\n external\\n override\\n {\\n // Initialize the requester request count for consistent request gas\\n // cost\\n if (requesterToRequestCountPlusOne[requester] == 0) {\\n requesterToRequestCountPlusOne[requester] = 1;\\n }\\n sponsorToRequesterToSponsorshipStatus[msg.sender][\\n requester\\n ] = sponsorshipStatus;\\n emit SetSponsorshipStatus(msg.sender, requester, sponsorshipStatus);\\n }\\n\\n /// @notice Called by the requester to make a request that refers to a\\n /// template for the Airnode address, endpoint ID and parameters\\n /// @dev `fulfillAddress` is not allowed to be the address of this\\n /// contract. This is not actually needed to protect users that use the\\n /// protocol as intended, but it is done for good measure.\\n /// @param templateId Template ID\\n /// @param sponsor Sponsor address\\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill the\\n /// request\\n /// @param fulfillAddress Address that will be called to fulfill\\n /// @param fulfillFunctionId Signature of the function that will be called\\n /// to fulfill\\n /// @param parameters Parameters provided by the requester in addition to\\n /// the parameters in the template\\n /// @return requestId Request ID\\n function makeTemplateRequest(\\n bytes32 templateId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata parameters\\n ) external override returns (bytes32 requestId) {\\n address airnode = templates[templateId].airnode;\\n // If the Airnode address of the template is zero the template does not\\n // exist because template creation does not allow zero Airnode address\\n require(airnode != address(0), \\\"Template does not exist\\\");\\n require(fulfillAddress != address(this), \\\"Fulfill address AirnodeRrp\\\");\\n require(\\n sponsorToRequesterToSponsorshipStatus[sponsor][msg.sender],\\n \\\"Requester not sponsored\\\"\\n );\\n uint256 requesterRequestCount = requesterToRequestCountPlusOne[\\n msg.sender\\n ];\\n requestId = keccak256(\\n abi.encodePacked(\\n block.chainid,\\n address(this),\\n msg.sender,\\n requesterRequestCount,\\n templateId,\\n sponsor,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId,\\n parameters\\n )\\n );\\n requestIdToFulfillmentParameters[requestId] = keccak256(\\n abi.encodePacked(\\n airnode,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId\\n )\\n );\\n requesterToRequestCountPlusOne[msg.sender]++;\\n emit MadeTemplateRequest(\\n airnode,\\n requestId,\\n requesterRequestCount,\\n block.chainid,\\n msg.sender,\\n templateId,\\n sponsor,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId,\\n parameters\\n );\\n }\\n\\n /// @notice Called by the requester to make a full request, which provides\\n /// all of its parameters as arguments and does not refer to a template\\n /// @dev `fulfillAddress` is not allowed to be the address of this\\n /// contract. This is not actually needed to protect users that use the\\n /// protocol as intended, but it is done for good measure.\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param sponsor Sponsor address\\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill\\n /// the request\\n /// @param fulfillAddress Address that will be called to fulfill\\n /// @param fulfillFunctionId Signature of the function that will be called\\n /// to fulfill\\n /// @param parameters All request parameters\\n /// @return requestId Request ID\\n function makeFullRequest(\\n address airnode,\\n bytes32 endpointId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata parameters\\n ) external override returns (bytes32 requestId) {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n require(fulfillAddress != address(this), \\\"Fulfill address AirnodeRrp\\\");\\n require(\\n sponsorToRequesterToSponsorshipStatus[sponsor][msg.sender],\\n \\\"Requester not sponsored\\\"\\n );\\n uint256 requesterRequestCount = requesterToRequestCountPlusOne[\\n msg.sender\\n ];\\n requestId = keccak256(\\n abi.encodePacked(\\n block.chainid,\\n address(this),\\n msg.sender,\\n requesterRequestCount,\\n airnode,\\n endpointId,\\n sponsor,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId,\\n parameters\\n )\\n );\\n requestIdToFulfillmentParameters[requestId] = keccak256(\\n abi.encodePacked(\\n airnode,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId\\n )\\n );\\n requesterToRequestCountPlusOne[msg.sender]++;\\n emit MadeFullRequest(\\n airnode,\\n requestId,\\n requesterRequestCount,\\n block.chainid,\\n msg.sender,\\n endpointId,\\n sponsor,\\n sponsorWallet,\\n fulfillAddress,\\n fulfillFunctionId,\\n parameters\\n );\\n }\\n\\n /// @notice Called by Airnode to fulfill the request (template or full)\\n /// @dev The data is ABI-encoded as a `bytes` type, with its format\\n /// depending on the request specifications.\\n /// This will not revert depending on the external call. However, it will\\n /// return `false` if the external call reverts or if there is no function\\n /// with a matching signature at `fulfillAddress`. On the other hand, it\\n /// will return `true` if the external call returns successfully or if\\n /// there is no contract deployed at `fulfillAddress`.\\n /// If `callSuccess` is `false`, `callData` can be decoded to retrieve the\\n /// revert string.\\n /// This function emits its event after an untrusted low-level call,\\n /// meaning that the order of these events within the transaction should\\n /// not be taken seriously, yet the content will be sound.\\n /// @param requestId Request ID\\n /// @param airnode Airnode address\\n /// @param data Fulfillment data\\n /// @param fulfillAddress Address that will be called to fulfill\\n /// @param fulfillFunctionId Signature of the function that will be called\\n /// to fulfill\\n /// @return callSuccess If the fulfillment call succeeded\\n /// @return callData Data returned by the fulfillment call (if there is\\n /// any)\\n function fulfill(\\n bytes32 requestId,\\n address airnode,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata data,\\n bytes calldata signature\\n ) external override returns (bool callSuccess, bytes memory callData) {\\n require(\\n keccak256(\\n abi.encodePacked(\\n airnode,\\n msg.sender,\\n fulfillAddress,\\n fulfillFunctionId\\n )\\n ) == requestIdToFulfillmentParameters[requestId],\\n \\\"Invalid request fulfillment\\\"\\n );\\n require(\\n (\\n keccak256(abi.encodePacked(requestId, data))\\n .toEthSignedMessageHash()\\n ).recover(signature) == airnode,\\n \\\"Invalid signature\\\"\\n );\\n delete requestIdToFulfillmentParameters[requestId];\\n (callSuccess, callData) = fulfillAddress.call( // solhint-disable-line avoid-low-level-calls\\n abi.encodeWithSelector(fulfillFunctionId, requestId, data)\\n );\\n if (callSuccess) {\\n emit FulfilledRequest(airnode, requestId, data);\\n } else {\\n // We do not bubble up the revert string from `callData`\\n emit FailedRequest(\\n airnode,\\n requestId,\\n \\\"Fulfillment failed unexpectedly\\\"\\n );\\n }\\n }\\n\\n /// @notice Called by Airnode if the request cannot be fulfilled\\n /// @dev Airnode should fall back to this if a request cannot be fulfilled\\n /// because static call to `fulfill()` returns `false` for `callSuccess`\\n /// @param requestId Request ID\\n /// @param airnode Airnode address\\n /// @param fulfillAddress Address that will be called to fulfill\\n /// @param fulfillFunctionId Signature of the function that will be called\\n /// to fulfill\\n /// @param errorMessage A message that explains why the request has failed\\n function fail(\\n bytes32 requestId,\\n address airnode,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n string calldata errorMessage\\n ) external override {\\n require(\\n keccak256(\\n abi.encodePacked(\\n airnode,\\n msg.sender,\\n fulfillAddress,\\n fulfillFunctionId\\n )\\n ) == requestIdToFulfillmentParameters[requestId],\\n \\\"Invalid request fulfillment\\\"\\n );\\n delete requestIdToFulfillmentParameters[requestId];\\n emit FailedRequest(airnode, requestId, errorMessage);\\n }\\n\\n /// @notice Called to check if the request with the ID is made but not\\n /// fulfilled/failed yet\\n /// @dev If a requester has made a request, received a request ID but did\\n /// not hear back, it can call this method to check if the Airnode has\\n /// called back `fail()` instead.\\n /// @param requestId Request ID\\n /// @return isAwaitingFulfillment If the request is awaiting fulfillment\\n /// (i.e., `true` if `fulfill()` or `fail()` is not called back yet,\\n /// `false` otherwise)\\n function requestIsAwaitingFulfillment(bytes32 requestId)\\n external\\n view\\n override\\n returns (bool isAwaitingFulfillment)\\n {\\n isAwaitingFulfillment =\\n requestIdToFulfillmentParameters[requestId] != bytes32(0);\\n }\\n}\\n\",\"keccak256\":\"0x7b770788b2ca3661f9617b887fef62aff0d795cd32e15dc61e05ada5637a1093\",\"license\":\"MIT\"},\"contracts/rrp/AuthorizationUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/IAuthorizationUtilsV0.sol\\\";\\nimport \\\"../authorizers/interfaces/IAuthorizerV0.sol\\\";\\n\\n/// @title Contract that implements authorization checks\\ncontract AuthorizationUtilsV0 is IAuthorizationUtilsV0 {\\n /// @notice Uses the authorizer contracts of an Airnode to decide if a\\n /// request is authorized. Once an Airnode receives a request, it calls\\n /// this method to determine if it should respond. Similarly, third parties\\n /// can use this method to determine if a particular request would be\\n /// authorized.\\n /// @dev This method is meant to be called off-chain, statically by the\\n /// Airnode to decide if it should respond to a request. The requester can\\n /// also call it, yet this function returning true should not be taken as a\\n /// guarantee of the subsequent request being fulfilled.\\n /// It is enough for only one of the authorizer contracts to return true\\n /// for the request to be authorized.\\n /// @param authorizers Authorizer contract addresses\\n /// @param airnode Airnode address\\n /// @param requestId Request ID\\n /// @param endpointId Endpoint ID\\n /// @param sponsor Sponsor address\\n /// @param requester Requester address\\n /// @return status Authorization status of the request\\n function checkAuthorizationStatus(\\n address[] calldata authorizers,\\n address airnode,\\n bytes32 requestId,\\n bytes32 endpointId,\\n address sponsor,\\n address requester\\n ) public view override returns (bool status) {\\n for (uint256 ind = 0; ind < authorizers.length; ind++) {\\n IAuthorizerV0 authorizer = IAuthorizerV0(authorizers[ind]);\\n if (\\n authorizer.isAuthorizedV0(\\n requestId,\\n airnode,\\n endpointId,\\n sponsor,\\n requester\\n )\\n ) {\\n return true;\\n }\\n }\\n return false;\\n }\\n\\n /// @notice A convenience function to make multiple authorization status\\n /// checks with a single call\\n /// @param authorizers Authorizer contract addresses\\n /// @param airnode Airnode address\\n /// @param requestIds Request IDs\\n /// @param endpointIds Endpoint IDs\\n /// @param sponsors Sponsor addresses\\n /// @param requesters Requester addresses\\n /// @return statuses Authorization statuses of the request\\n function checkAuthorizationStatuses(\\n address[] calldata authorizers,\\n address airnode,\\n bytes32[] calldata requestIds,\\n bytes32[] calldata endpointIds,\\n address[] calldata sponsors,\\n address[] calldata requesters\\n ) external view override returns (bool[] memory statuses) {\\n require(\\n requestIds.length == endpointIds.length &&\\n requestIds.length == sponsors.length &&\\n requestIds.length == requesters.length,\\n \\\"Unequal parameter lengths\\\"\\n );\\n statuses = new bool[](requestIds.length);\\n for (uint256 ind = 0; ind < requestIds.length; ind++) {\\n statuses[ind] = checkAuthorizationStatus(\\n authorizers,\\n airnode,\\n requestIds[ind],\\n endpointIds[ind],\\n sponsors[ind],\\n requesters[ind]\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa3419ee8a4146a7716355e835102700bfdd12928ab83790d368a344e7819a502\",\"license\":\"MIT\"},\"contracts/rrp/TemplateUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/ITemplateUtilsV0.sol\\\";\\n\\n/// @title Contract that implements request templates\\ncontract TemplateUtilsV0 is ITemplateUtilsV0 {\\n struct Template {\\n address airnode;\\n bytes32 endpointId;\\n bytes parameters;\\n }\\n\\n /// @notice Called to get a template\\n mapping(bytes32 => Template) public override templates;\\n\\n /// @notice Creates a request template with the given parameters,\\n /// addressable by the ID it returns\\n /// @dev A specific set of request parameters will always have the same\\n /// template ID. This means a few things: (1) You can compute the expected\\n /// ID of a template before creating it, (2) Creating a new template with\\n /// the same parameters will overwrite the old one and return the same ID,\\n /// (3) After you query a template with its ID, you can verify its\\n /// integrity by applying the hash and comparing the result with the ID.\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param parameters Static request parameters (i.e., parameters that will\\n /// not change between requests, unlike the dynamic parameters determined\\n /// at request-time)\\n /// @return templateId Request template ID\\n function createTemplate(\\n address airnode,\\n bytes32 endpointId,\\n bytes calldata parameters\\n ) external override returns (bytes32 templateId) {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n templateId = keccak256(\\n abi.encodePacked(airnode, endpointId, parameters)\\n );\\n templates[templateId] = Template({\\n airnode: airnode,\\n endpointId: endpointId,\\n parameters: parameters\\n });\\n emit CreatedTemplate(templateId, airnode, endpointId, parameters);\\n }\\n\\n /// @notice A convenience method to retrieve multiple templates with a\\n /// single call\\n /// @dev Does not revert if the templates being indexed do not exist\\n /// @param templateIds Request template IDs\\n /// @return airnodes Array of Airnode addresses\\n /// @return endpointIds Array of endpoint IDs\\n /// @return parameters Array of request parameters\\n function getTemplates(bytes32[] calldata templateIds)\\n external\\n view\\n override\\n returns (\\n address[] memory airnodes,\\n bytes32[] memory endpointIds,\\n bytes[] memory parameters\\n )\\n {\\n airnodes = new address[](templateIds.length);\\n endpointIds = new bytes32[](templateIds.length);\\n parameters = new bytes[](templateIds.length);\\n for (uint256 ind = 0; ind < templateIds.length; ind++) {\\n Template storage template = templates[templateIds[ind]];\\n airnodes[ind] = template.airnode;\\n endpointIds[ind] = template.endpointId;\\n parameters[ind] = template.parameters;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x6196d12fd828783a299819b75ab3cdf10e84d39b8d8419be28b613e10a7a7602\",\"license\":\"MIT\"},\"contracts/rrp/WithdrawalUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/IWithdrawalUtilsV0.sol\\\";\\n\\n/// @title Contract that implements logic for withdrawals from sponsor wallets\\ncontract WithdrawalUtilsV0 is IWithdrawalUtilsV0 {\\n /// @notice Called to get the withdrawal request count of the sponsor\\n /// @dev Can be used to calculate the ID of the next withdrawal request the\\n /// sponsor will make\\n mapping(address => uint256) public override sponsorToWithdrawalRequestCount;\\n\\n /// @dev Hash of expected fulfillment parameters are kept to verify that\\n /// the fulfillment will be done with the correct parameters\\n mapping(bytes32 => bytes32) private withdrawalRequestIdToParameters;\\n\\n /// @notice Called by a sponsor to create a request for the Airnode to send\\n /// the funds kept in the respective sponsor wallet to the sponsor\\n /// @dev We do not need to use the withdrawal request parameters in the\\n /// request ID hash to validate them at the node-side because all of the\\n /// parameters are used during fulfillment and will get validated on-chain.\\n /// The first withdrawal request a sponsor will make will cost slightly\\n /// higher gas than the rest due to how the request counter is implemented.\\n /// @param airnode Airnode address\\n /// @param sponsorWallet Sponsor wallet that the withdrawal is requested\\n /// from\\n function requestWithdrawal(address airnode, address sponsorWallet)\\n external\\n override\\n {\\n bytes32 withdrawalRequestId = keccak256(\\n abi.encodePacked(\\n block.chainid,\\n address(this),\\n msg.sender,\\n ++sponsorToWithdrawalRequestCount[msg.sender]\\n )\\n );\\n withdrawalRequestIdToParameters[withdrawalRequestId] = keccak256(\\n abi.encodePacked(airnode, msg.sender, sponsorWallet)\\n );\\n emit RequestedWithdrawal(\\n airnode,\\n msg.sender,\\n withdrawalRequestId,\\n sponsorWallet\\n );\\n }\\n\\n /// @notice Called by the Airnode using the sponsor wallet to fulfill the\\n /// withdrawal request made by the sponsor\\n /// @dev The Airnode sends the funds to the sponsor through this method\\n /// to emit an event that indicates that the withdrawal request has been\\n /// fulfilled\\n /// @param withdrawalRequestId Withdrawal request ID\\n /// @param airnode Airnode address\\n /// @param sponsor Sponsor address\\n function fulfillWithdrawal(\\n bytes32 withdrawalRequestId,\\n address airnode,\\n address sponsor\\n ) external payable override {\\n require(\\n withdrawalRequestIdToParameters[withdrawalRequestId] ==\\n keccak256(abi.encodePacked(airnode, sponsor, msg.sender)),\\n \\\"Invalid withdrawal fulfillment\\\"\\n );\\n delete withdrawalRequestIdToParameters[withdrawalRequestId];\\n emit FulfilledWithdrawal(\\n airnode,\\n sponsor,\\n withdrawalRequestId,\\n msg.sender,\\n msg.value\\n );\\n (bool success, ) = sponsor.call{value: msg.value}(\\\"\\\"); // solhint-disable-line avoid-low-level-calls\\n require(success, \\\"Transfer failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0x45f937dd2b57942913d4ab1c0e08356fd57cd3d2cca013604adbb8de0e0c898b\",\"license\":\"MIT\"},\"contracts/rrp/interfaces/IAirnodeRrpV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAuthorizationUtilsV0.sol\\\";\\nimport \\\"./ITemplateUtilsV0.sol\\\";\\nimport \\\"./IWithdrawalUtilsV0.sol\\\";\\n\\ninterface IAirnodeRrpV0 is\\n IAuthorizationUtilsV0,\\n ITemplateUtilsV0,\\n IWithdrawalUtilsV0\\n{\\n event SetSponsorshipStatus(\\n address indexed sponsor,\\n address indexed requester,\\n bool sponsorshipStatus\\n );\\n\\n event MadeTemplateRequest(\\n address indexed airnode,\\n bytes32 indexed requestId,\\n uint256 requesterRequestCount,\\n uint256 chainId,\\n address requester,\\n bytes32 templateId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes parameters\\n );\\n\\n event MadeFullRequest(\\n address indexed airnode,\\n bytes32 indexed requestId,\\n uint256 requesterRequestCount,\\n uint256 chainId,\\n address requester,\\n bytes32 endpointId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes parameters\\n );\\n\\n event FulfilledRequest(\\n address indexed airnode,\\n bytes32 indexed requestId,\\n bytes data\\n );\\n\\n event FailedRequest(\\n address indexed airnode,\\n bytes32 indexed requestId,\\n string errorMessage\\n );\\n\\n function setSponsorshipStatus(address requester, bool sponsorshipStatus)\\n external;\\n\\n function makeTemplateRequest(\\n bytes32 templateId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata parameters\\n ) external returns (bytes32 requestId);\\n\\n function makeFullRequest(\\n address airnode,\\n bytes32 endpointId,\\n address sponsor,\\n address sponsorWallet,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata parameters\\n ) external returns (bytes32 requestId);\\n\\n function fulfill(\\n bytes32 requestId,\\n address airnode,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata data,\\n bytes calldata signature\\n ) external returns (bool callSuccess, bytes memory callData);\\n\\n function fail(\\n bytes32 requestId,\\n address airnode,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n string calldata errorMessage\\n ) external;\\n\\n function sponsorToRequesterToSponsorshipStatus(\\n address sponsor,\\n address requester\\n ) external view returns (bool sponsorshipStatus);\\n\\n function requesterToRequestCountPlusOne(address requester)\\n external\\n view\\n returns (uint256 requestCountPlusOne);\\n\\n function requestIsAwaitingFulfillment(bytes32 requestId)\\n external\\n view\\n returns (bool isAwaitingFulfillment);\\n}\\n\",\"keccak256\":\"0x5306571db1377e8c9dd8cb6e6c7a8deaa2d8ec540e7b2b229e9db5aa5da21277\",\"license\":\"MIT\"},\"contracts/rrp/interfaces/IAuthorizationUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IAuthorizationUtilsV0 {\\n function checkAuthorizationStatus(\\n address[] calldata authorizers,\\n address airnode,\\n bytes32 requestId,\\n bytes32 endpointId,\\n address sponsor,\\n address requester\\n ) external view returns (bool status);\\n\\n function checkAuthorizationStatuses(\\n address[] calldata authorizers,\\n address airnode,\\n bytes32[] calldata requestIds,\\n bytes32[] calldata endpointIds,\\n address[] calldata sponsors,\\n address[] calldata requesters\\n ) external view returns (bool[] memory statuses);\\n}\\n\",\"keccak256\":\"0x597a40e9911628f6bc1d845c9ebe7c345833e8814caa5ce02a8597d3b4ee7975\",\"license\":\"MIT\"},\"contracts/rrp/interfaces/ITemplateUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface ITemplateUtilsV0 {\\n event CreatedTemplate(\\n bytes32 indexed templateId,\\n address airnode,\\n bytes32 endpointId,\\n bytes parameters\\n );\\n\\n function createTemplate(\\n address airnode,\\n bytes32 endpointId,\\n bytes calldata parameters\\n ) external returns (bytes32 templateId);\\n\\n function getTemplates(bytes32[] calldata templateIds)\\n external\\n view\\n returns (\\n address[] memory airnodes,\\n bytes32[] memory endpointIds,\\n bytes[] memory parameters\\n );\\n\\n function templates(bytes32 templateId)\\n external\\n view\\n returns (\\n address airnode,\\n bytes32 endpointId,\\n bytes memory parameters\\n );\\n}\\n\",\"keccak256\":\"0x4212b264303a78b3c3ed0230cf23b7c3ca58bccec936eccd1d4924347b0fea47\",\"license\":\"MIT\"},\"contracts/rrp/interfaces/IWithdrawalUtilsV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IWithdrawalUtilsV0 {\\n event RequestedWithdrawal(\\n address indexed airnode,\\n address indexed sponsor,\\n bytes32 indexed withdrawalRequestId,\\n address sponsorWallet\\n );\\n\\n event FulfilledWithdrawal(\\n address indexed airnode,\\n address indexed sponsor,\\n bytes32 indexed withdrawalRequestId,\\n address sponsorWallet,\\n uint256 amount\\n );\\n\\n function requestWithdrawal(address airnode, address sponsorWallet) external;\\n\\n function fulfillWithdrawal(\\n bytes32 withdrawalRequestId,\\n address airnode,\\n address sponsor\\n ) external payable;\\n\\n function sponsorToWithdrawalRequestCount(address sponsor)\\n external\\n view\\n returns (uint256 withdrawalRequestCount);\\n}\\n\",\"keccak256\":\"0x732a3a2447150d8a8097042719ca1faf35e06cbfec364d1d6b17aae254cfd520\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5061274d806100206000396000f3fe6080604052600436106100f35760003560e01c806376428c9b1161008a578063acbe180011610059578063acbe1800146102f7578063addf027c14610317578063ca31d58614610337578063f8fa73a11461036457600080fd5b806376428c9b146102405780637e7166f31461026f5780638a33be011461029c578063a81e9f79146102bc57600080fd5b80633c7fe5e3116100c65780633c7fe5e3146101ae57806350743bb9146101c157806352e41f99146102005780636e6be03f1461022057600080fd5b80630a631576146100f85780631d414cbd146101305780631decbf181461015257806332393f2b14610180575b600080fd5b34801561010457600080fd5b50610118610113366004611bd0565b610391565b60405161012793929190611c41565b60405180910390f35b34801561013c57600080fd5b5061015061014b366004611c8e565b610446565b005b34801561015e57600080fd5b5061017261016d366004611d1b565b610566565b604051610127929190611dc6565b34801561018c57600080fd5b506101a061019b366004611de9565b6108d8565b604051908152602001610127565b6101506101bc366004611e43565b610a68565b3480156101cd57600080fd5b506101f06101dc366004611bd0565b600090815260056020526040902054151590565b6040519015158152602001610127565b34801561020c57600080fd5b5061015061021b366004611e7f565b610c15565b34801561022c57600080fd5b506101a061023b366004611efe565b610d30565b34801561024c57600080fd5b5061026061025b366004611fcf565b610fa4565b60405161012793929190612069565b34801561027b57600080fd5b506101a061028a366004612100565b60046020526000908152604090205481565b3480156102a857600080fd5b506101f06102b7366004612122565b6111ed565b3480156102c857600080fd5b506101f06102d7366004611c8e565b600360209081526000928352604080842090915290825290205460ff1681565b34801561030357600080fd5b506101a06103123660046121ab565b61130a565b34801561032357600080fd5b50610150610332366004612249565b611589565b34801561034357600080fd5b50610357610352366004612280565b61162f565b6040516101279190612384565b34801561037057600080fd5b506101a061037f366004612100565b60016020526000908152604090205481565b6000602081905290815260409020805460018201546002830180546001600160a01b039093169391926103c3906123ca565b80601f01602080910402602001604051908101604052809291908181526020018280546103ef906123ca565b801561043c5780601f106104115761010080835404028352916020019161043c565b820191906000526020600020905b81548152906001019060200180831161041f57829003601f168201915b5050505050905083565b336000818152600160205260408120805491924692309290859061046990612405565b91829055506040805160208101959095526bffffffffffffffffffffffff19606094851b8116918601919091529190921b166054830152606882015260880160408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606087811b82169385019390935233831b811660348501529185901b90911660488301529150605c0160408051808303601f19018152828252805160209182012060008581526002835292909220919091556001600160a01b03848116835283923392918716917fd48d52c7c6d0c940f3f8d07591e1800ef3a70daf79929a97ccd80b4494769fc7910160405180910390a4505050565b60008881526005602090815260408083205490516bffffffffffffffffffffffff1960608c811b82169483019490945233841b811660348301528a841b1660488201526001600160e01b03198916605c820152820160405160208183030381529060405280519060200120146106235760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e74000000000060448201526064015b60405180910390fd5b886001600160a01b03166106e585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516106df925061067f91508f908c908c9060200161243d565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b906117b0565b6001600160a01b03161461073b5760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e6174757265000000000000000000000000000000604482015260640161061a565b60008a81526005602052604080822091909155516001600160a01b03891690889061076e908d908a908a90602401612480565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516107c1919061249a565b6000604051808303816000865af19150503d80600081146107fe576040519150601f19603f3d011682016040523d82523d6000602084013e610803565b606091505b50909250905081156108585789896001600160a01b03167fc0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a888860405161084b9291906124b6565b60405180910390a36108cb565b89896001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc6040516108c2906020808252601f908201527f46756c66696c6c6d656e74206661696c656420756e65787065637465646c7900604082015260600190565b60405180910390a35b9850989650505050505050565b60006001600160a01b0385166109305760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b8484848460405160200161094794939291906124ca565b6040516020818303038152906040528051906020012090506040518060600160405280866001600160a01b0316815260200185815260200184848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509390945250508381526020818152604091829020845181547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178155848201516001820155918401518051929350610a1e9260028501929190910190611b37565b50905050807fba204bad31c4ec4b9b54164af94ae10c4e7312f22c0f9c065d6319c928ec9e7a86868686604051610a5894939291906124fd565b60405180910390a2949350505050565b6040516bffffffffffffffffffffffff19606084811b8216602084015283811b8216603484015233901b166048820152605c0160408051601f1981840301815291815281516020928301206000868152600290935291205414610b0d5760405162461bcd60e51b815260206004820152601e60248201527f496e76616c6964207769746864726177616c2066756c66696c6c6d656e740000604482015260640161061a565b6000838152600260209081526040808320929092558151338152349181019190915284916001600160a01b0380851692908616917fadb4840bbd5f924665ae7e0e0c83de5c0fb40a98c9b57dba53a6c978127a622e910160405180910390a46000816001600160a01b03163460405160006040518083038185875af1925050503d8060008114610bb9576040519150601f19603f3d011682016040523d82523d6000602084013e610bbe565b606091505b5050905080610c0f5760405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c65640000000000000000000000000000000000604482015260640161061a565b50505050565b6000868152600560209081526040918290205491516bffffffffffffffffffffffff19606089811b82169383019390935233831b8116603483015287831b1660488201526001600160e01b03198616605c820152016040516020818303038152906040528051906020012014610ccd5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e740000000000604482015260640161061a565b600560008781526020019081526020016000206000905585856001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc8484604051610d209291906124b6565b60405180910390a3505050505050565b60006001600160a01b038916610d885760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b6001600160a01b038516301415610de15760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038716600090815260036020908152604080832033845290915290205460ff16610e545760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d8d604051602001610ea59c9b9a99989796959493929190612530565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff1960608e811b8216938501939093528a831b8116603485015289831b1660488401526001600160e01b03198816605c84015293500160408051601f1981840301815291815281516020928301206000858152600584528281209190915533815260049092528120805491610f3e83612405565b9190505550818a6001600160a01b03167f3a52c462346de2e9436a3868970892956828a11b9c43da1ed43740b12e1125ae8346338e8e8e8e8e8e8e604051610f8f9a999897969594939291906125bf565b60405180910390a35098975050505050505050565b606080808367ffffffffffffffff811115610fc157610fc1612631565b604051908082528060200260200182016040528015610fea578160200160208202803683370190505b5092508367ffffffffffffffff81111561100657611006612631565b60405190808252806020026020018201604052801561102f578160200160208202803683370190505b5091508367ffffffffffffffff81111561104b5761104b612631565b60405190808252806020026020018201604052801561107e57816020015b60608152602001906001900390816110695790505b50905060005b848110156111e55760008060008888858181106110a3576110a3612647565b90506020020135815260200190815260200160002090508060000160009054906101000a90046001600160a01b03168583815181106110e4576110e4612647565b60200260200101906001600160a01b031690816001600160a01b031681525050806001015484838151811061111b5761111b612647565b602002602001018181525050806002018054611136906123ca565b80601f0160208091040260200160405190810160405280929190818152602001828054611162906123ca565b80156111af5780601f10611184576101008083540402835291602001916111af565b820191906000526020600020905b81548152906001019060200180831161119257829003601f168201915b50505050508383815181106111c6576111c6612647565b60200260200101819052505080806111dd90612405565b915050611084565b509250925092565b6000805b878110156112f957600089898381811061120d5761120d612647565b90506020020160208101906112229190612100565b6040517f29b915b3000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b038a811660248301526044820189905287811660648301528681166084830152919250908216906329b915b39060a40160206040518083038186803b15801561129e57600080fd5b505afa1580156112b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d6919061265d565b156112e6576001925050506112ff565b50806112f181612405565b9150506111f1565b50600090505b979650505050505050565b6000878152602081905260408120546001600160a01b03168061136f5760405162461bcd60e51b815260206004820152601760248201527f54656d706c61746520646f6573206e6f74206578697374000000000000000000604482015260640161061a565b6001600160a01b0386163014156113c85760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038816600090815260036020908152604080832033845290915290205460ff1661143b5760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d60405160200161148a9b9a9998979695949392919061267a565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606086811b8216938501939093528b831b811660348501528a831b1660488401526001600160e01b03198916605c84015294500160408051601f198184030181529181528151602092830120600086815260058452828120919091553381526004909252812080549161152383612405565b919050555082826001600160a01b03167feb39930cdcbb560e6422558a2468b93a215af60063622e63cbb165eba14c32038346338f8f8f8f8f8f8f6040516115749a999897969594939291906125bf565b60405180910390a35050979650505050505050565b6001600160a01b0382166000908152600460205260409020546115c3576001600160a01b0382166000908152600460205260409020600190555b3360008181526003602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917fc2e532a12bbcce2bfa2ef9e4bee80180e4e1b1f78618f0d20bc49a648b577c56910160405180910390a35050565b6060878614801561163f57508784145b801561164a57508782145b6116965760405162461bcd60e51b815260206004820152601960248201527f556e657175616c20706172616d65746572206c656e6774687300000000000000604482015260640161061a565b8767ffffffffffffffff8111156116af576116af612631565b6040519080825280602002602001820160405280156116d8578160200160208202803683370190505b50905060005b888110156117a05761176c8d8d8d8d8d868181106116fe576116fe612647565b905060200201358c8c8781811061171757611717612647565b905060200201358b8b8881811061173057611730612647565b90506020020160208101906117459190612100565b8a8a8981811061175757611757612647565b90506020020160208101906102b79190612100565b82828151811061177e5761177e612647565b911515602092830291909101909101528061179881612405565b9150506116de565b509b9a5050505050505050505050565b60008060006117bf85856117d4565b915091506117cc81611844565b509392505050565b60008082516041141561180b5760208301516040840151606085015160001a6117ff87828585611a02565b9450945050505061183d565b825160401415611835576020830151604084015161182a868383611aef565b93509350505061183d565b506000905060025b9250929050565b600081600481111561185857611858612701565b14156118615750565b600181600481111561187557611875612701565b14156118c35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161061a565b60028160048111156118d7576118d7612701565b14156119255760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161061a565b600381600481111561193957611939612701565b14156119925760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161061a565b60048160048111156119a6576119a6612701565b14156119ff5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161061a565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611a395750600090506003611ae6565b8460ff16601b14158015611a5157508460ff16601c14155b15611a625750600090506004611ae6565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611ab6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611adf57600060019250925050611ae6565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b01611b2987828885611a02565b935093505050935093915050565b828054611b43906123ca565b90600052602060002090601f016020900481019282611b655760008555611bab565b82601f10611b7e57805160ff1916838001178555611bab565b82800160010185558215611bab579182015b82811115611bab578251825591602001919060010190611b90565b50611bb7929150611bbb565b5090565b5b80821115611bb75760008155600101611bbc565b600060208284031215611be257600080fd5b5035919050565b60005b83811015611c04578181015183820152602001611bec565b83811115610c0f5750506000910152565b60008151808452611c2d816020860160208601611be9565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201526000611c696060830184611c15565b95945050505050565b80356001600160a01b0381168114611c8957600080fd5b919050565b60008060408385031215611ca157600080fd5b611caa83611c72565b9150611cb860208401611c72565b90509250929050565b80356001600160e01b031981168114611c8957600080fd5b60008083601f840112611ceb57600080fd5b50813567ffffffffffffffff811115611d0357600080fd5b60208301915083602082850101111561183d57600080fd5b60008060008060008060008060c0898b031215611d3757600080fd5b88359750611d4760208a01611c72565b9650611d5560408a01611c72565b9550611d6360608a01611cc1565b9450608089013567ffffffffffffffff80821115611d8057600080fd5b611d8c8c838d01611cd9565b909650945060a08b0135915080821115611da557600080fd5b50611db28b828c01611cd9565b999c989b5096995094979396929594505050565b8215158152604060208201526000611de16040830184611c15565b949350505050565b60008060008060608587031215611dff57600080fd5b611e0885611c72565b935060208501359250604085013567ffffffffffffffff811115611e2b57600080fd5b611e3787828801611cd9565b95989497509550505050565b600080600060608486031215611e5857600080fd5b83359250611e6860208501611c72565b9150611e7660408501611c72565b90509250925092565b60008060008060008060a08789031215611e9857600080fd5b86359550611ea860208801611c72565b9450611eb660408801611c72565b9350611ec460608801611cc1565b9250608087013567ffffffffffffffff811115611ee057600080fd5b611eec89828a01611cd9565b979a9699509497509295939492505050565b60008060008060008060008060e0898b031215611f1a57600080fd5b611f2389611c72565b975060208901359650611f3860408a01611c72565b9550611f4660608a01611c72565b9450611f5460808a01611c72565b9350611f6260a08a01611cc1565b925060c089013567ffffffffffffffff811115611f7e57600080fd5b611db28b828c01611cd9565b60008083601f840112611f9c57600080fd5b50813567ffffffffffffffff811115611fb457600080fd5b6020830191508360208260051b850101111561183d57600080fd5b60008060208385031215611fe257600080fd5b823567ffffffffffffffff811115611ff957600080fd5b61200585828601611f8a565b90969095509350505050565b600082825180855260208086019550808260051b84010181860160005b8481101561205c57601f1986840301895261204a838351611c15565b9884019892509083019060010161202e565b5090979650505050505050565b606080825284519082018190526000906020906080840190828801845b828110156120ab5781516001600160a01b031684529284019290840190600101612086565b5050508381038285015285518082528683019183019060005b818110156120e0578351835292840192918401916001016120c4565b505084810360408601526120f48187612011565b98975050505050505050565b60006020828403121561211257600080fd5b61211b82611c72565b9392505050565b600080600080600080600060c0888a03121561213d57600080fd5b873567ffffffffffffffff81111561215457600080fd5b6121608a828b01611f8a565b9098509650612173905060208901611c72565b9450604088013593506060880135925061218f60808901611c72565b915061219d60a08901611c72565b905092959891949750929550565b600080600080600080600060c0888a0312156121c657600080fd5b873596506121d660208901611c72565b95506121e460408901611c72565b94506121f260608901611c72565b935061220060808901611cc1565b925060a088013567ffffffffffffffff81111561221c57600080fd5b6122288a828b01611cd9565b989b979a50959850939692959293505050565b80151581146119ff57600080fd5b6000806040838503121561225c57600080fd5b61226583611c72565b915060208301356122758161223b565b809150509250929050565b600080600080600080600080600080600060c08c8e0312156122a157600080fd5b67ffffffffffffffff808d3511156122b857600080fd5b6122c58e8e358f01611f8a565b909c509a506122d660208e01611c72565b99508060408e013511156122e957600080fd5b6122f98e60408f01358f01611f8a565b909950975060608d013581101561230f57600080fd5b61231f8e60608f01358f01611f8a565b909750955060808d013581101561233557600080fd5b6123458e60808f01358f01611f8a565b909550935060a08d013581101561235b57600080fd5b5061236c8d60a08e01358e01611f8a565b81935080925050509295989b509295989b9093969950565b6020808252825182820181905260009190848201906040850190845b818110156123be5783511515835292840192918401916001016123a0565b50909695505050505050565b600181811c908216806123de57607f821691505b602082108114156123ff57634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561242757634e487b7160e01b600052601160045260246000fd5b5060010190565b81818437506000910190815290565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000611c69604083018486612457565b600082516124ac818460208701611be9565b9190910192915050565b602081526000611de1602083018486612457565b6bffffffffffffffffffffffff198560601b16815283601482015281836034830137600091016034019081529392505050565b6001600160a01b0385168152836020820152606060408201526000612526606083018486612457565b9695505050505050565b8c815260006bffffffffffffffffffffffff196060818f821b166020850152818e821b1660348501528c6048850152818c821b1660688501528a607c850152818a821b16609c8501528189821b1660b08501528188821b1660c485015250506001600160e01b0319851660d88301526125ad60dc8301848661242e565b9e9d5050505050505050505050505050565b60006101208c83528b60208401526001600160a01b03808c1660408501528a6060850152808a16608085015280891660a085015280881660c0850152506001600160e01b0319861660e0840152806101008401526126208184018587612457565b9d9c50505050505050505050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561266f57600080fd5b815161211b8161223b565b8b815260006bffffffffffffffffffffffff19808d60601b166020840152808c60601b1660348401528a6048840152896068840152808960601b166088840152808860601b16609c840152808760601b1660b0840152506001600160e01b0319851660c4830152828460c8840137506000910160c8019081529a9950505050505050505050565b634e487b7160e01b600052602160045260246000fdfea26469706673582212208125c69072f5b73d89af7cc14fb8da75fc37036277de16e38207c96e9f01298764736f6c63430008090033", + "deployedBytecode": "0x6080604052600436106100f35760003560e01c806376428c9b1161008a578063acbe180011610059578063acbe1800146102f7578063addf027c14610317578063ca31d58614610337578063f8fa73a11461036457600080fd5b806376428c9b146102405780637e7166f31461026f5780638a33be011461029c578063a81e9f79146102bc57600080fd5b80633c7fe5e3116100c65780633c7fe5e3146101ae57806350743bb9146101c157806352e41f99146102005780636e6be03f1461022057600080fd5b80630a631576146100f85780631d414cbd146101305780631decbf181461015257806332393f2b14610180575b600080fd5b34801561010457600080fd5b50610118610113366004611bd0565b610391565b60405161012793929190611c41565b60405180910390f35b34801561013c57600080fd5b5061015061014b366004611c8e565b610446565b005b34801561015e57600080fd5b5061017261016d366004611d1b565b610566565b604051610127929190611dc6565b34801561018c57600080fd5b506101a061019b366004611de9565b6108d8565b604051908152602001610127565b6101506101bc366004611e43565b610a68565b3480156101cd57600080fd5b506101f06101dc366004611bd0565b600090815260056020526040902054151590565b6040519015158152602001610127565b34801561020c57600080fd5b5061015061021b366004611e7f565b610c15565b34801561022c57600080fd5b506101a061023b366004611efe565b610d30565b34801561024c57600080fd5b5061026061025b366004611fcf565b610fa4565b60405161012793929190612069565b34801561027b57600080fd5b506101a061028a366004612100565b60046020526000908152604090205481565b3480156102a857600080fd5b506101f06102b7366004612122565b6111ed565b3480156102c857600080fd5b506101f06102d7366004611c8e565b600360209081526000928352604080842090915290825290205460ff1681565b34801561030357600080fd5b506101a06103123660046121ab565b61130a565b34801561032357600080fd5b50610150610332366004612249565b611589565b34801561034357600080fd5b50610357610352366004612280565b61162f565b6040516101279190612384565b34801561037057600080fd5b506101a061037f366004612100565b60016020526000908152604090205481565b6000602081905290815260409020805460018201546002830180546001600160a01b039093169391926103c3906123ca565b80601f01602080910402602001604051908101604052809291908181526020018280546103ef906123ca565b801561043c5780601f106104115761010080835404028352916020019161043c565b820191906000526020600020905b81548152906001019060200180831161041f57829003601f168201915b5050505050905083565b336000818152600160205260408120805491924692309290859061046990612405565b91829055506040805160208101959095526bffffffffffffffffffffffff19606094851b8116918601919091529190921b166054830152606882015260880160408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606087811b82169385019390935233831b811660348501529185901b90911660488301529150605c0160408051808303601f19018152828252805160209182012060008581526002835292909220919091556001600160a01b03848116835283923392918716917fd48d52c7c6d0c940f3f8d07591e1800ef3a70daf79929a97ccd80b4494769fc7910160405180910390a4505050565b60008881526005602090815260408083205490516bffffffffffffffffffffffff1960608c811b82169483019490945233841b811660348301528a841b1660488201526001600160e01b03198916605c820152820160405160208183030381529060405280519060200120146106235760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e74000000000060448201526064015b60405180910390fd5b886001600160a01b03166106e585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516106df925061067f91508f908c908c9060200161243d565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b906117b0565b6001600160a01b03161461073b5760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e6174757265000000000000000000000000000000604482015260640161061a565b60008a81526005602052604080822091909155516001600160a01b03891690889061076e908d908a908a90602401612480565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516107c1919061249a565b6000604051808303816000865af19150503d80600081146107fe576040519150601f19603f3d011682016040523d82523d6000602084013e610803565b606091505b50909250905081156108585789896001600160a01b03167fc0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a888860405161084b9291906124b6565b60405180910390a36108cb565b89896001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc6040516108c2906020808252601f908201527f46756c66696c6c6d656e74206661696c656420756e65787065637465646c7900604082015260600190565b60405180910390a35b9850989650505050505050565b60006001600160a01b0385166109305760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b8484848460405160200161094794939291906124ca565b6040516020818303038152906040528051906020012090506040518060600160405280866001600160a01b0316815260200185815260200184848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509390945250508381526020818152604091829020845181547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178155848201516001820155918401518051929350610a1e9260028501929190910190611b37565b50905050807fba204bad31c4ec4b9b54164af94ae10c4e7312f22c0f9c065d6319c928ec9e7a86868686604051610a5894939291906124fd565b60405180910390a2949350505050565b6040516bffffffffffffffffffffffff19606084811b8216602084015283811b8216603484015233901b166048820152605c0160408051601f1981840301815291815281516020928301206000868152600290935291205414610b0d5760405162461bcd60e51b815260206004820152601e60248201527f496e76616c6964207769746864726177616c2066756c66696c6c6d656e740000604482015260640161061a565b6000838152600260209081526040808320929092558151338152349181019190915284916001600160a01b0380851692908616917fadb4840bbd5f924665ae7e0e0c83de5c0fb40a98c9b57dba53a6c978127a622e910160405180910390a46000816001600160a01b03163460405160006040518083038185875af1925050503d8060008114610bb9576040519150601f19603f3d011682016040523d82523d6000602084013e610bbe565b606091505b5050905080610c0f5760405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c65640000000000000000000000000000000000604482015260640161061a565b50505050565b6000868152600560209081526040918290205491516bffffffffffffffffffffffff19606089811b82169383019390935233831b8116603483015287831b1660488201526001600160e01b03198616605c820152016040516020818303038152906040528051906020012014610ccd5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e740000000000604482015260640161061a565b600560008781526020019081526020016000206000905585856001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc8484604051610d209291906124b6565b60405180910390a3505050505050565b60006001600160a01b038916610d885760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b6001600160a01b038516301415610de15760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038716600090815260036020908152604080832033845290915290205460ff16610e545760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d8d604051602001610ea59c9b9a99989796959493929190612530565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff1960608e811b8216938501939093528a831b8116603485015289831b1660488401526001600160e01b03198816605c84015293500160408051601f1981840301815291815281516020928301206000858152600584528281209190915533815260049092528120805491610f3e83612405565b9190505550818a6001600160a01b03167f3a52c462346de2e9436a3868970892956828a11b9c43da1ed43740b12e1125ae8346338e8e8e8e8e8e8e604051610f8f9a999897969594939291906125bf565b60405180910390a35098975050505050505050565b606080808367ffffffffffffffff811115610fc157610fc1612631565b604051908082528060200260200182016040528015610fea578160200160208202803683370190505b5092508367ffffffffffffffff81111561100657611006612631565b60405190808252806020026020018201604052801561102f578160200160208202803683370190505b5091508367ffffffffffffffff81111561104b5761104b612631565b60405190808252806020026020018201604052801561107e57816020015b60608152602001906001900390816110695790505b50905060005b848110156111e55760008060008888858181106110a3576110a3612647565b90506020020135815260200190815260200160002090508060000160009054906101000a90046001600160a01b03168583815181106110e4576110e4612647565b60200260200101906001600160a01b031690816001600160a01b031681525050806001015484838151811061111b5761111b612647565b602002602001018181525050806002018054611136906123ca565b80601f0160208091040260200160405190810160405280929190818152602001828054611162906123ca565b80156111af5780601f10611184576101008083540402835291602001916111af565b820191906000526020600020905b81548152906001019060200180831161119257829003601f168201915b50505050508383815181106111c6576111c6612647565b60200260200101819052505080806111dd90612405565b915050611084565b509250925092565b6000805b878110156112f957600089898381811061120d5761120d612647565b90506020020160208101906112229190612100565b6040517f29b915b3000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b038a811660248301526044820189905287811660648301528681166084830152919250908216906329b915b39060a40160206040518083038186803b15801561129e57600080fd5b505afa1580156112b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d6919061265d565b156112e6576001925050506112ff565b50806112f181612405565b9150506111f1565b50600090505b979650505050505050565b6000878152602081905260408120546001600160a01b03168061136f5760405162461bcd60e51b815260206004820152601760248201527f54656d706c61746520646f6573206e6f74206578697374000000000000000000604482015260640161061a565b6001600160a01b0386163014156113c85760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038816600090815260036020908152604080832033845290915290205460ff1661143b5760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d60405160200161148a9b9a9998979695949392919061267a565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606086811b8216938501939093528b831b811660348501528a831b1660488401526001600160e01b03198916605c84015294500160408051601f198184030181529181528151602092830120600086815260058452828120919091553381526004909252812080549161152383612405565b919050555082826001600160a01b03167feb39930cdcbb560e6422558a2468b93a215af60063622e63cbb165eba14c32038346338f8f8f8f8f8f8f6040516115749a999897969594939291906125bf565b60405180910390a35050979650505050505050565b6001600160a01b0382166000908152600460205260409020546115c3576001600160a01b0382166000908152600460205260409020600190555b3360008181526003602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917fc2e532a12bbcce2bfa2ef9e4bee80180e4e1b1f78618f0d20bc49a648b577c56910160405180910390a35050565b6060878614801561163f57508784145b801561164a57508782145b6116965760405162461bcd60e51b815260206004820152601960248201527f556e657175616c20706172616d65746572206c656e6774687300000000000000604482015260640161061a565b8767ffffffffffffffff8111156116af576116af612631565b6040519080825280602002602001820160405280156116d8578160200160208202803683370190505b50905060005b888110156117a05761176c8d8d8d8d8d868181106116fe576116fe612647565b905060200201358c8c8781811061171757611717612647565b905060200201358b8b8881811061173057611730612647565b90506020020160208101906117459190612100565b8a8a8981811061175757611757612647565b90506020020160208101906102b79190612100565b82828151811061177e5761177e612647565b911515602092830291909101909101528061179881612405565b9150506116de565b509b9a5050505050505050505050565b60008060006117bf85856117d4565b915091506117cc81611844565b509392505050565b60008082516041141561180b5760208301516040840151606085015160001a6117ff87828585611a02565b9450945050505061183d565b825160401415611835576020830151604084015161182a868383611aef565b93509350505061183d565b506000905060025b9250929050565b600081600481111561185857611858612701565b14156118615750565b600181600481111561187557611875612701565b14156118c35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161061a565b60028160048111156118d7576118d7612701565b14156119255760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161061a565b600381600481111561193957611939612701565b14156119925760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161061a565b60048160048111156119a6576119a6612701565b14156119ff5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161061a565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611a395750600090506003611ae6565b8460ff16601b14158015611a5157508460ff16601c14155b15611a625750600090506004611ae6565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611ab6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611adf57600060019250925050611ae6565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b01611b2987828885611a02565b935093505050935093915050565b828054611b43906123ca565b90600052602060002090601f016020900481019282611b655760008555611bab565b82601f10611b7e57805160ff1916838001178555611bab565b82800160010185558215611bab579182015b82811115611bab578251825591602001919060010190611b90565b50611bb7929150611bbb565b5090565b5b80821115611bb75760008155600101611bbc565b600060208284031215611be257600080fd5b5035919050565b60005b83811015611c04578181015183820152602001611bec565b83811115610c0f5750506000910152565b60008151808452611c2d816020860160208601611be9565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201526000611c696060830184611c15565b95945050505050565b80356001600160a01b0381168114611c8957600080fd5b919050565b60008060408385031215611ca157600080fd5b611caa83611c72565b9150611cb860208401611c72565b90509250929050565b80356001600160e01b031981168114611c8957600080fd5b60008083601f840112611ceb57600080fd5b50813567ffffffffffffffff811115611d0357600080fd5b60208301915083602082850101111561183d57600080fd5b60008060008060008060008060c0898b031215611d3757600080fd5b88359750611d4760208a01611c72565b9650611d5560408a01611c72565b9550611d6360608a01611cc1565b9450608089013567ffffffffffffffff80821115611d8057600080fd5b611d8c8c838d01611cd9565b909650945060a08b0135915080821115611da557600080fd5b50611db28b828c01611cd9565b999c989b5096995094979396929594505050565b8215158152604060208201526000611de16040830184611c15565b949350505050565b60008060008060608587031215611dff57600080fd5b611e0885611c72565b935060208501359250604085013567ffffffffffffffff811115611e2b57600080fd5b611e3787828801611cd9565b95989497509550505050565b600080600060608486031215611e5857600080fd5b83359250611e6860208501611c72565b9150611e7660408501611c72565b90509250925092565b60008060008060008060a08789031215611e9857600080fd5b86359550611ea860208801611c72565b9450611eb660408801611c72565b9350611ec460608801611cc1565b9250608087013567ffffffffffffffff811115611ee057600080fd5b611eec89828a01611cd9565b979a9699509497509295939492505050565b60008060008060008060008060e0898b031215611f1a57600080fd5b611f2389611c72565b975060208901359650611f3860408a01611c72565b9550611f4660608a01611c72565b9450611f5460808a01611c72565b9350611f6260a08a01611cc1565b925060c089013567ffffffffffffffff811115611f7e57600080fd5b611db28b828c01611cd9565b60008083601f840112611f9c57600080fd5b50813567ffffffffffffffff811115611fb457600080fd5b6020830191508360208260051b850101111561183d57600080fd5b60008060208385031215611fe257600080fd5b823567ffffffffffffffff811115611ff957600080fd5b61200585828601611f8a565b90969095509350505050565b600082825180855260208086019550808260051b84010181860160005b8481101561205c57601f1986840301895261204a838351611c15565b9884019892509083019060010161202e565b5090979650505050505050565b606080825284519082018190526000906020906080840190828801845b828110156120ab5781516001600160a01b031684529284019290840190600101612086565b5050508381038285015285518082528683019183019060005b818110156120e0578351835292840192918401916001016120c4565b505084810360408601526120f48187612011565b98975050505050505050565b60006020828403121561211257600080fd5b61211b82611c72565b9392505050565b600080600080600080600060c0888a03121561213d57600080fd5b873567ffffffffffffffff81111561215457600080fd5b6121608a828b01611f8a565b9098509650612173905060208901611c72565b9450604088013593506060880135925061218f60808901611c72565b915061219d60a08901611c72565b905092959891949750929550565b600080600080600080600060c0888a0312156121c657600080fd5b873596506121d660208901611c72565b95506121e460408901611c72565b94506121f260608901611c72565b935061220060808901611cc1565b925060a088013567ffffffffffffffff81111561221c57600080fd5b6122288a828b01611cd9565b989b979a50959850939692959293505050565b80151581146119ff57600080fd5b6000806040838503121561225c57600080fd5b61226583611c72565b915060208301356122758161223b565b809150509250929050565b600080600080600080600080600080600060c08c8e0312156122a157600080fd5b67ffffffffffffffff808d3511156122b857600080fd5b6122c58e8e358f01611f8a565b909c509a506122d660208e01611c72565b99508060408e013511156122e957600080fd5b6122f98e60408f01358f01611f8a565b909950975060608d013581101561230f57600080fd5b61231f8e60608f01358f01611f8a565b909750955060808d013581101561233557600080fd5b6123458e60808f01358f01611f8a565b909550935060a08d013581101561235b57600080fd5b5061236c8d60a08e01358e01611f8a565b81935080925050509295989b509295989b9093969950565b6020808252825182820181905260009190848201906040850190845b818110156123be5783511515835292840192918401916001016123a0565b50909695505050505050565b600181811c908216806123de57607f821691505b602082108114156123ff57634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561242757634e487b7160e01b600052601160045260246000fd5b5060010190565b81818437506000910190815290565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000611c69604083018486612457565b600082516124ac818460208701611be9565b9190910192915050565b602081526000611de1602083018486612457565b6bffffffffffffffffffffffff198560601b16815283601482015281836034830137600091016034019081529392505050565b6001600160a01b0385168152836020820152606060408201526000612526606083018486612457565b9695505050505050565b8c815260006bffffffffffffffffffffffff196060818f821b166020850152818e821b1660348501528c6048850152818c821b1660688501528a607c850152818a821b16609c8501528189821b1660b08501528188821b1660c485015250506001600160e01b0319851660d88301526125ad60dc8301848661242e565b9e9d5050505050505050505050505050565b60006101208c83528b60208401526001600160a01b03808c1660408501528a6060850152808a16608085015280891660a085015280881660c0850152506001600160e01b0319861660e0840152806101008401526126208184018587612457565b9d9c50505050505050505050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561266f57600080fd5b815161211b8161223b565b8b815260006bffffffffffffffffffffffff19808d60601b166020840152808c60601b1660348401528a6048840152896068840152808960601b166088840152808860601b16609c840152808760601b1660b0840152506001600160e01b0319851660c4830152828460c8840137506000910160c8019081529a9950505050505050505050565b634e487b7160e01b600052602160045260246000fdfea26469706673582212208125c69072f5b73d89af7cc14fb8da75fc37036277de16e38207c96e9f01298764736f6c63430008090033", + "devdoc": { + "kind": "dev", + "methods": { + "checkAuthorizationStatus(address[],address,bytes32,bytes32,address,address)": { + "details": "This method is meant to be called off-chain, statically by the Airnode to decide if it should respond to a request. The requester can also call it, yet this function returning true should not be taken as a guarantee of the subsequent request being fulfilled. It is enough for only one of the authorizer contracts to return true for the request to be authorized.", + "params": { + "airnode": "Airnode address", + "authorizers": "Authorizer contract addresses", + "endpointId": "Endpoint ID", + "requestId": "Request ID", + "requester": "Requester address", + "sponsor": "Sponsor address" + }, + "returns": { + "status": "Authorization status of the request" + } + }, + "checkAuthorizationStatuses(address[],address,bytes32[],bytes32[],address[],address[])": { + "params": { + "airnode": "Airnode address", + "authorizers": "Authorizer contract addresses", + "endpointIds": "Endpoint IDs", + "requestIds": "Request IDs", + "requesters": "Requester addresses", + "sponsors": "Sponsor addresses" + }, + "returns": { + "statuses": "Authorization statuses of the request" + } + }, + "createTemplate(address,bytes32,bytes)": { + "details": "A specific set of request parameters will always have the same template ID. This means a few things: (1) You can compute the expected ID of a template before creating it, (2) Creating a new template with the same parameters will overwrite the old one and return the same ID, (3) After you query a template with its ID, you can verify its integrity by applying the hash and comparing the result with the ID.", + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID (allowed to be `bytes32(0)`)", + "parameters": "Static request parameters (i.e., parameters that will not change between requests, unlike the dynamic parameters determined at request-time)" + }, + "returns": { + "templateId": "Request template ID" + } + }, + "fail(bytes32,address,address,bytes4,string)": { + "details": "Airnode should fall back to this if a request cannot be fulfilled because static call to `fulfill()` returns `false` for `callSuccess`", + "params": { + "airnode": "Airnode address", + "errorMessage": "A message that explains why the request has failed", + "fulfillAddress": "Address that will be called to fulfill", + "fulfillFunctionId": "Signature of the function that will be called to fulfill", + "requestId": "Request ID" + } + }, + "fulfill(bytes32,address,address,bytes4,bytes,bytes)": { + "details": "The data is ABI-encoded as a `bytes` type, with its format depending on the request specifications. This will not revert depending on the external call. However, it will return `false` if the external call reverts or if there is no function with a matching signature at `fulfillAddress`. On the other hand, it will return `true` if the external call returns successfully or if there is no contract deployed at `fulfillAddress`. If `callSuccess` is `false`, `callData` can be decoded to retrieve the revert string. This function emits its event after an untrusted low-level call, meaning that the order of these events within the transaction should not be taken seriously, yet the content will be sound.", + "params": { + "airnode": "Airnode address", + "data": "Fulfillment data", + "fulfillAddress": "Address that will be called to fulfill", + "fulfillFunctionId": "Signature of the function that will be called to fulfill", + "requestId": "Request ID" + }, + "returns": { + "callData": "Data returned by the fulfillment call (if there is any)", + "callSuccess": "If the fulfillment call succeeded" + } + }, + "fulfillWithdrawal(bytes32,address,address)": { + "details": "The Airnode sends the funds to the sponsor through this method to emit an event that indicates that the withdrawal request has been fulfilled", + "params": { + "airnode": "Airnode address", + "sponsor": "Sponsor address", + "withdrawalRequestId": "Withdrawal request ID" + } + }, + "getTemplates(bytes32[])": { + "details": "Does not revert if the templates being indexed do not exist", + "params": { + "templateIds": "Request template IDs" + }, + "returns": { + "airnodes": "Array of Airnode addresses", + "endpointIds": "Array of endpoint IDs", + "parameters": "Array of request parameters" + } + }, + "makeFullRequest(address,bytes32,address,address,address,bytes4,bytes)": { + "details": "`fulfillAddress` is not allowed to be the address of this contract. This is not actually needed to protect users that use the protocol as intended, but it is done for good measure.", + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID (allowed to be `bytes32(0)`)", + "fulfillAddress": "Address that will be called to fulfill", + "fulfillFunctionId": "Signature of the function that will be called to fulfill", + "parameters": "All request parameters", + "sponsor": "Sponsor address", + "sponsorWallet": "Sponsor wallet that is requested to fulfill the request" + }, + "returns": { + "requestId": "Request ID" + } + }, + "makeTemplateRequest(bytes32,address,address,address,bytes4,bytes)": { + "details": "`fulfillAddress` is not allowed to be the address of this contract. This is not actually needed to protect users that use the protocol as intended, but it is done for good measure.", + "params": { + "fulfillAddress": "Address that will be called to fulfill", + "fulfillFunctionId": "Signature of the function that will be called to fulfill", + "parameters": "Parameters provided by the requester in addition to the parameters in the template", + "sponsor": "Sponsor address", + "sponsorWallet": "Sponsor wallet that is requested to fulfill the request", + "templateId": "Template ID" + }, + "returns": { + "requestId": "Request ID" + } + }, + "requestIsAwaitingFulfillment(bytes32)": { + "details": "If a requester has made a request, received a request ID but did not hear back, it can call this method to check if the Airnode has called back `fail()` instead.", + "params": { + "requestId": "Request ID" + }, + "returns": { + "isAwaitingFulfillment": "If the request is awaiting fulfillment (i.e., `true` if `fulfill()` or `fail()` is not called back yet, `false` otherwise)" + } + }, + "requestWithdrawal(address,address)": { + "details": "We do not need to use the withdrawal request parameters in the request ID hash to validate them at the node-side because all of the parameters are used during fulfillment and will get validated on-chain. The first withdrawal request a sponsor will make will cost slightly higher gas than the rest due to how the request counter is implemented.", + "params": { + "airnode": "Airnode address", + "sponsorWallet": "Sponsor wallet that the withdrawal is requested from" + } + }, + "setSponsorshipStatus(address,bool)": { + "details": "This is not Airnode-specific, i.e., the sponsor allows the requester's requests to be fulfilled through its sponsor wallets across all Airnodes", + "params": { + "requester": "Requester address", + "sponsorshipStatus": "Sponsorship status" + } + } + }, + "stateVariables": { + "requestIdToFulfillmentParameters": { + "details": "Hash of expected fulfillment parameters are kept to verify that the fulfillment will be done with the correct parameters. This value is also used to check if the fulfillment for the particular request is expected, i.e., if there are recorded fulfillment parameters." + }, + "requesterToRequestCountPlusOne": { + "details": "Can be used to calculate the ID of the next request the requester will make" + } + }, + "title": "Contract that implements the Airnode request–response protocol (RRP)", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "checkAuthorizationStatus(address[],address,bytes32,bytes32,address,address)": { + "notice": "Uses the authorizer contracts of an Airnode to decide if a request is authorized. Once an Airnode receives a request, it calls this method to determine if it should respond. Similarly, third parties can use this method to determine if a particular request would be authorized." + }, + "checkAuthorizationStatuses(address[],address,bytes32[],bytes32[],address[],address[])": { + "notice": "A convenience function to make multiple authorization status checks with a single call" + }, + "createTemplate(address,bytes32,bytes)": { + "notice": "Creates a request template with the given parameters, addressable by the ID it returns" + }, + "fail(bytes32,address,address,bytes4,string)": { + "notice": "Called by Airnode if the request cannot be fulfilled" + }, + "fulfill(bytes32,address,address,bytes4,bytes,bytes)": { + "notice": "Called by Airnode to fulfill the request (template or full)" + }, + "fulfillWithdrawal(bytes32,address,address)": { + "notice": "Called by the Airnode using the sponsor wallet to fulfill the withdrawal request made by the sponsor" + }, + "getTemplates(bytes32[])": { + "notice": "A convenience method to retrieve multiple templates with a single call" + }, + "makeFullRequest(address,bytes32,address,address,address,bytes4,bytes)": { + "notice": "Called by the requester to make a full request, which provides all of its parameters as arguments and does not refer to a template" + }, + "makeTemplateRequest(bytes32,address,address,address,bytes4,bytes)": { + "notice": "Called by the requester to make a request that refers to a template for the Airnode address, endpoint ID and parameters" + }, + "requestIsAwaitingFulfillment(bytes32)": { + "notice": "Called to check if the request with the ID is made but not fulfilled/failed yet" + }, + "requestWithdrawal(address,address)": { + "notice": "Called by a sponsor to create a request for the Airnode to send the funds kept in the respective sponsor wallet to the sponsor" + }, + "requesterToRequestCountPlusOne(address)": { + "notice": "Called to get the request count of the requester plus one" + }, + "setSponsorshipStatus(address,bool)": { + "notice": "Called by the sponsor to set the sponsorship status of a requester, i.e., allow or disallow a requester to make requests that will be fulfilled by the sponsor wallet" + }, + "sponsorToRequesterToSponsorshipStatus(address,address)": { + "notice": "Called to get the sponsorship status for a sponsor–requester pair" + }, + "sponsorToWithdrawalRequestCount(address)": { + "notice": "Called to get the withdrawal request count of the sponsor" + }, + "templates(bytes32)": { + "notice": "Called to get a template" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 3643, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "templates", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_struct(Template)3636_storage)" + }, + { + "astId": 3796, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "sponsorToWithdrawalRequestCount", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 3801, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "withdrawalRequestIdToParameters", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_bytes32,t_bytes32)" + }, + { + "astId": 2913, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "sponsorToRequesterToSponsorshipStatus", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_mapping(t_address,t_bool))" + }, + { + "astId": 2919, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "requesterToRequestCountPlusOne", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 2924, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "requestIdToFulfillmentParameters", + "offset": 0, + "slot": "5", + "type": "t_mapping(t_bytes32,t_bytes32)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_bytes_storage": { + "encoding": "bytes", + "label": "bytes", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_mapping(t_address,t_bool))": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => mapping(address => bool))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_bool)" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_mapping(t_bytes32,t_bytes32)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => bytes32)", + "numberOfBytes": "32", + "value": "t_bytes32" + }, + "t_mapping(t_bytes32,t_struct(Template)3636_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct TemplateUtilsV0.Template)", + "numberOfBytes": "32", + "value": "t_struct(Template)3636_storage" + }, + "t_struct(Template)3636_storage": { + "encoding": "inplace", + "label": "struct TemplateUtilsV0.Template", + "members": [ + { + "astId": 3631, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "airnode", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 3633, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "endpointId", + "offset": 0, + "slot": "1", + "type": "t_bytes32" + }, + { + "astId": 3635, + "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", + "label": "parameters", + "offset": 0, + "slot": "2", + "type": "t_bytes_storage" + } + ], + "numberOfBytes": "96" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/packages/airnode-protocol/deployments/lightlink/AirnodeRrpV0DryRun.json b/packages/airnode-protocol/deployments/lightlink/AirnodeRrpV0DryRun.json new file mode 100644 index 0000000000..3a4818637b --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink/AirnodeRrpV0DryRun.json @@ -0,0 +1,163 @@ +{ + "address": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "FulfilledRequest", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "address", + "name": "fulfillAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "fulfillFunctionId", + "type": "bytes4" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "fulfill", + "outputs": [ + { + "internalType": "bool", + "name": "callSuccess", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x80aac67ee756c31cf21ed2814d7b0929751cfedbbd8b370da306bafd989869c3", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xc97965EbD0f2123Cc31BEc63E18A8Ce9Ef6a1e7e", + "contractAddress": "0x0000000000000000000000000000000000000000", + "transactionIndex": 0, + "gasUsed": "583060", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xf53d7a82385cd7dd7ac4ae5a1d4687ba134c90f107351c0e0e6d15f96f00c3cd", + "transactionHash": "0x80aac67ee756c31cf21ed2814d7b0929751cfedbbd8b370da306bafd989869c3", + "logs": [], + "blockNumber": 54178474, + "cumulativeGasUsed": "583060", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "d8591a026515856ab7bc7dc284bf2fbe", + "metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FulfilledRequest\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fulfillAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"fulfillFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"callSuccess\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Typically, contracts are built to revert when an external call they make reverts. In contrast, AirnodeRrpV0 does not revert when the external call during the fulfillment reverts, and instead fails gracefully by emitting a `FailedRequest` event. This event signals to the future invocations of the stateless Airnode to not retry the failed fulfillment. Although this approach meets the intended purpose, it disables Airnode from calling `eth_estimateGas` on `fulfill()` to estimate the gas amount that will be used to execute a fulfillment successfully. Specifically, since `eth_estimateGas` looks for the lowest gas limit that results in the transaction not reverting, and AirnodeRrpV0's `fulfill()` does not revert when its external call reverts (because it runs out of gas), `eth_estimateGas` will not necessarily return a gas amount that will result in the fulfillment to be successful even if such an amount exists. As a solution, Airnode calls `eth_estimateGas` on AirnodeRrpV0DryRun's `fulfill()` and the external call of the fulfillment, and add these up to find the gas limit required to execute a successful fulfillment. This sum is an overestimation of the actual requirement, as it includes an additional base fee (21,000 gas on Ethereum).\",\"kind\":\"dev\",\"methods\":{\"fulfill(bytes32,address,address,bytes4,bytes,bytes)\":{\"details\":\"Refer to AirnodeRrpV0's `fulfill()` for more information\",\"params\":{\"airnode\":\"Airnode address\",\"data\":\"Fulfillment data\",\"fulfillAddress\":\"Address that will be called to fulfill\",\"fulfillFunctionId\":\"Signature of the function that will be called to fulfill\",\"requestId\":\"Request ID\"},\"returns\":{\"callData\":\"Data returned by the fulfillment call (if there is any)\",\"callSuccess\":\"If the fulfillment call succeeded\"}}},\"stateVariables\":{\"requestIdToFulfillmentParameters\":{\"details\":\"This mapping is kept as it is in AirnodeRrpV0 to closely simulate the fulfillment. All of its keys will map to zero values.\"}},\"title\":\"Contract that complements Airnode request\\u2013response protocol (RRP) to allow Airnode to estimate the gas required to execute a fulfillment\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"fulfill(bytes32,address,address,bytes4,bytes,bytes)\":{\"notice\":\"Used by Airnode to estimate the gas amount needed to fulfill the request (excluding the external call). Do not call this function, as it will have no practical effect.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/rrp/AirnodeRrpV0DryRun.sol\":\"AirnodeRrpV0DryRun\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s;\\n uint8 v;\\n assembly {\\n s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\\n v := add(shr(255, vs), 27)\\n }\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xe9e291de7ffe06e66503c6700b1bb84ff6e0989cbb974653628d8994e7c97f03\",\"license\":\"MIT\"},\"contracts/rrp/AirnodeRrpV0DryRun.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\n\\n/// @title Contract that complements Airnode request\\u2013response protocol (RRP) to\\n/// allow Airnode to estimate the gas required to execute a fulfillment\\n/// @dev Typically, contracts are built to revert when an external call they\\n/// make reverts. In contrast, AirnodeRrpV0 does not revert when the external\\n/// call during the fulfillment reverts, and instead fails gracefully by\\n/// emitting a `FailedRequest` event. This event signals to the future\\n/// invocations of the stateless Airnode to not retry the failed fulfillment.\\n/// Although this approach meets the intended purpose, it disables Airnode from\\n/// calling `eth_estimateGas` on `fulfill()` to estimate the gas amount that\\n/// will be used to execute a fulfillment successfully. Specifically, since\\n/// `eth_estimateGas` looks for the lowest gas limit that results in the\\n/// transaction not reverting, and AirnodeRrpV0's `fulfill()` does not revert\\n/// when its external call reverts (because it runs out of gas),\\n/// `eth_estimateGas` will not necessarily return a gas amount that will result\\n/// in the fulfillment to be successful even if such an amount exists.\\n/// As a solution, Airnode calls `eth_estimateGas` on AirnodeRrpV0DryRun's\\n/// `fulfill()` and the external call of the fulfillment, and add these up to\\n/// find the gas limit required to execute a successful fulfillment. This\\n/// sum is an overestimation of the actual requirement, as it includes an\\n/// additional base fee (21,000 gas on Ethereum).\\ncontract AirnodeRrpV0DryRun\\n{\\n using ECDSA for bytes32;\\n\\n event FulfilledRequest(\\n address indexed airnode,\\n bytes32 indexed requestId,\\n bytes data\\n );\\n\\n /// @dev This mapping is kept as it is in AirnodeRrpV0 to closely simulate\\n /// the fulfillment. All of its keys will map to zero values.\\n mapping(bytes32 => bytes32) private requestIdToFulfillmentParameters;\\n\\n /// @notice Used by Airnode to estimate the gas amount needed to fulfill\\n /// the request (excluding the external call). Do not call this function,\\n /// as it will have no practical effect.\\n /// @dev Refer to AirnodeRrpV0's `fulfill()` for more information\\n /// @param requestId Request ID\\n /// @param airnode Airnode address\\n /// @param data Fulfillment data\\n /// @param fulfillAddress Address that will be called to fulfill\\n /// @param fulfillFunctionId Signature of the function that will be called\\n /// to fulfill\\n /// @return callSuccess If the fulfillment call succeeded\\n /// @return callData Data returned by the fulfillment call (if there is\\n /// any)\\n function fulfill(\\n bytes32 requestId,\\n address airnode,\\n address fulfillAddress,\\n bytes4 fulfillFunctionId,\\n bytes calldata data,\\n bytes calldata signature\\n ) external returns (bool callSuccess, bytes memory callData) {\\n // The line below is kept the same, except that the condition is\\n // reversed to ensure that it never reverts. All\\n // `requestIdToFulfillmentParameters` values are zero and virtually no\\n // `keccak256()` output will be equal to that.\\n require(\\n keccak256(\\n abi.encodePacked(\\n airnode,\\n msg.sender,\\n fulfillAddress,\\n fulfillFunctionId\\n )\\n ) != requestIdToFulfillmentParameters[requestId],\\n \\\"Dummy revert string\\\"\\n );\\n // The line below does not need to be modified\\n require(\\n (\\n keccak256(abi.encodePacked(requestId, data))\\n .toEthSignedMessageHash()\\n ).recover(signature) == airnode,\\n \\\"Invalid signature\\\"\\n );\\n // We cannot call `fulfillAddress` below because (1) we do not want\\n // this function to actually fulfill the request (2) the fulfill\\n // function will be behind an `onlyAirnodeRrp` modifier and will reject\\n // the calls from AirnodeRrpV0DryRun.\\n // Instead, we call an address that we know to not contain any\\n // bytecode, which will result in the call to not revert or spend extra\\n // gas. Since we have already confirmed that `airnode` has signed a\\n // hash, it is guaranteed to be an EOA and we can use it as a dummy\\n // call target.\\n (callSuccess, callData) = airnode.call( // solhint-disable-line avoid-low-level-calls\\n abi.encodeWithSelector(fulfillFunctionId, requestId, data)\\n );\\n // If the external call above does not succeed, the `eth_estimateGas`\\n // called on the external call will not be able to return a gas amount.\\n // AirnodeRrpV0DryRun's `fulfill()` optimistically estimates the\\n // AirnodeRrpV0 overhead of a fulfillment, and expects Airnode to\\n // detect if the external call will succeed (by calling\\n // `eth_estimateGas` on it) independently. Therefore, we do not need to\\n // consider the unhappy path here.\\n if (callSuccess) {\\n emit FulfilledRequest(airnode, requestId, data);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x5a3243f6e878bc2dbc853033bac3b73ba9aea70b02db49cca9a7e837cf24b170\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50610997806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80631decbf1814610030575b600080fd5b61004361003e366004610756565b61005a565b604051610051929190610858565b60405180910390f35b6000888152602081815260408083205490516bffffffffffffffffffffffff1960608c811b82169483019490945233841b811660348301528a841b1660488201527fffffffff000000000000000000000000000000000000000000000000000000008916605c820152820160405160208183030381529060405280519060200120141561012e5760405162461bcd60e51b815260206004820152601360248201527f44756d6d792072657665727420737472696e670000000000000000000000000060448201526064015b60405180910390fd5b886001600160a01b03166101f085858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516101ea925061018a91508f908c908c90602001610894565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90610371565b6001600160a01b0316146102465760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610125565b886001600160a01b0316878b8888604051602401610266939291906108d7565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516102d191906108fa565b6000604051808303816000865af19150503d806000811461030e576040519150601f19603f3d011682016040523d82523d6000602084013e610313565b606091505b50909250905081156103645789896001600160a01b03167fc0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a888860405161035b929190610916565b60405180910390a35b9850989650505050505050565b60008060006103808585610395565b9150915061038d81610405565b509392505050565b6000808251604114156103cc5760208301516040840151606085015160001a6103c0878285856105c3565b945094505050506103fe565b8251604014156103f657602083015160408401516103eb8683836106b0565b9350935050506103fe565b506000905060025b9250929050565b600081600481111561041957610419610932565b14156104225750565b600181600481111561043657610436610932565b14156104845760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610125565b600281600481111561049857610498610932565b14156104e65760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610125565b60038160048111156104fa576104fa610932565b14156105535760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610125565b600481600481111561056757610567610932565b14156105c05760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610125565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156105fa57506000905060036106a7565b8460ff16601b1415801561061257508460ff16601c14155b1561062357506000905060046106a7565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610677573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166106a0576000600192509250506106a7565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b016106ea878288856105c3565b935093505050935093915050565b80356001600160a01b038116811461070f57600080fd5b919050565b60008083601f84011261072657600080fd5b50813567ffffffffffffffff81111561073e57600080fd5b6020830191508360208285010111156103fe57600080fd5b60008060008060008060008060c0898b03121561077257600080fd5b8835975061078260208a016106f8565b965061079060408a016106f8565b955060608901357fffffffff00000000000000000000000000000000000000000000000000000000811681146107c557600080fd5b9450608089013567ffffffffffffffff808211156107e257600080fd5b6107ee8c838d01610714565b909650945060a08b013591508082111561080757600080fd5b506108148b828c01610714565b999c989b5096995094979396929594505050565b60005b8381101561084357818101518382015260200161082b565b83811115610852576000848401525b50505050565b8215158152604060208201526000825180604084015261087f816060850160208701610828565b601f01601f1916919091016060019392505050565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8381526040602082015260006108f16040830184866108ae565b95945050505050565b6000825161090c818460208701610828565b9190910192915050565b60208152600061092a6020830184866108ae565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212201f6f9d6bb1fa5e17ffc6a138eebeb4fdd93d3c2b7fe4bcc141ddae7c7708cb6464736f6c63430008090033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c80631decbf1814610030575b600080fd5b61004361003e366004610756565b61005a565b604051610051929190610858565b60405180910390f35b6000888152602081815260408083205490516bffffffffffffffffffffffff1960608c811b82169483019490945233841b811660348301528a841b1660488201527fffffffff000000000000000000000000000000000000000000000000000000008916605c820152820160405160208183030381529060405280519060200120141561012e5760405162461bcd60e51b815260206004820152601360248201527f44756d6d792072657665727420737472696e670000000000000000000000000060448201526064015b60405180910390fd5b886001600160a01b03166101f085858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516101ea925061018a91508f908c908c90602001610894565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90610371565b6001600160a01b0316146102465760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610125565b886001600160a01b0316878b8888604051602401610266939291906108d7565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516102d191906108fa565b6000604051808303816000865af19150503d806000811461030e576040519150601f19603f3d011682016040523d82523d6000602084013e610313565b606091505b50909250905081156103645789896001600160a01b03167fc0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a888860405161035b929190610916565b60405180910390a35b9850989650505050505050565b60008060006103808585610395565b9150915061038d81610405565b509392505050565b6000808251604114156103cc5760208301516040840151606085015160001a6103c0878285856105c3565b945094505050506103fe565b8251604014156103f657602083015160408401516103eb8683836106b0565b9350935050506103fe565b506000905060025b9250929050565b600081600481111561041957610419610932565b14156104225750565b600181600481111561043657610436610932565b14156104845760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610125565b600281600481111561049857610498610932565b14156104e65760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610125565b60038160048111156104fa576104fa610932565b14156105535760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610125565b600481600481111561056757610567610932565b14156105c05760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610125565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156105fa57506000905060036106a7565b8460ff16601b1415801561061257508460ff16601c14155b1561062357506000905060046106a7565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610677573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166106a0576000600192509250506106a7565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b016106ea878288856105c3565b935093505050935093915050565b80356001600160a01b038116811461070f57600080fd5b919050565b60008083601f84011261072657600080fd5b50813567ffffffffffffffff81111561073e57600080fd5b6020830191508360208285010111156103fe57600080fd5b60008060008060008060008060c0898b03121561077257600080fd5b8835975061078260208a016106f8565b965061079060408a016106f8565b955060608901357fffffffff00000000000000000000000000000000000000000000000000000000811681146107c557600080fd5b9450608089013567ffffffffffffffff808211156107e257600080fd5b6107ee8c838d01610714565b909650945060a08b013591508082111561080757600080fd5b506108148b828c01610714565b999c989b5096995094979396929594505050565b60005b8381101561084357818101518382015260200161082b565b83811115610852576000848401525b50505050565b8215158152604060208201526000825180604084015261087f816060850160208701610828565b601f01601f1916919091016060019392505050565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8381526040602082015260006108f16040830184866108ae565b95945050505050565b6000825161090c818460208701610828565b9190910192915050565b60208152600061092a6020830184866108ae565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212201f6f9d6bb1fa5e17ffc6a138eebeb4fdd93d3c2b7fe4bcc141ddae7c7708cb6464736f6c63430008090033", + "devdoc": { + "details": "Typically, contracts are built to revert when an external call they make reverts. In contrast, AirnodeRrpV0 does not revert when the external call during the fulfillment reverts, and instead fails gracefully by emitting a `FailedRequest` event. This event signals to the future invocations of the stateless Airnode to not retry the failed fulfillment. Although this approach meets the intended purpose, it disables Airnode from calling `eth_estimateGas` on `fulfill()` to estimate the gas amount that will be used to execute a fulfillment successfully. Specifically, since `eth_estimateGas` looks for the lowest gas limit that results in the transaction not reverting, and AirnodeRrpV0's `fulfill()` does not revert when its external call reverts (because it runs out of gas), `eth_estimateGas` will not necessarily return a gas amount that will result in the fulfillment to be successful even if such an amount exists. As a solution, Airnode calls `eth_estimateGas` on AirnodeRrpV0DryRun's `fulfill()` and the external call of the fulfillment, and add these up to find the gas limit required to execute a successful fulfillment. This sum is an overestimation of the actual requirement, as it includes an additional base fee (21,000 gas on Ethereum).", + "kind": "dev", + "methods": { + "fulfill(bytes32,address,address,bytes4,bytes,bytes)": { + "details": "Refer to AirnodeRrpV0's `fulfill()` for more information", + "params": { + "airnode": "Airnode address", + "data": "Fulfillment data", + "fulfillAddress": "Address that will be called to fulfill", + "fulfillFunctionId": "Signature of the function that will be called to fulfill", + "requestId": "Request ID" + }, + "returns": { + "callData": "Data returned by the fulfillment call (if there is any)", + "callSuccess": "If the fulfillment call succeeded" + } + } + }, + "stateVariables": { + "requestIdToFulfillmentParameters": { + "details": "This mapping is kept as it is in AirnodeRrpV0 to closely simulate the fulfillment. All of its keys will map to zero values." + } + }, + "title": "Contract that complements Airnode request–response protocol (RRP) to allow Airnode to estimate the gas required to execute a fulfillment", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "fulfill(bytes32,address,address,bytes4,bytes,bytes)": { + "notice": "Used by Airnode to estimate the gas amount needed to fulfill the request (excluding the external call). Do not call this function, as it will have no practical effect." + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 3386, + "contract": "contracts/rrp/AirnodeRrpV0DryRun.sol:AirnodeRrpV0DryRun", + "label": "requestIdToFulfillmentParameters", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_bytes32)" + } + ], + "types": { + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_bytes32)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => bytes32)", + "numberOfBytes": "32", + "value": "t_bytes32" + } + } + } +} diff --git a/packages/airnode-protocol/deployments/lightlink/RequesterAuthorizerWithAirnode.json b/packages/airnode-protocol/deployments/lightlink/RequesterAuthorizerWithAirnode.json new file mode 100644 index 0000000000..8e55427d82 --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink/RequesterAuthorizerWithAirnode.json @@ -0,0 +1,912 @@ +{ + "address": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_accessControlRegistry", + "type": "address" + }, + { + "internalType": "string", + "name": "_adminRoleDescription", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + } + ], + "name": "ExtendedWhitelistExpiration", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "setter", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint192", + "name": "indefiniteWhitelistCount", + "type": "uint192" + } + ], + "name": "RevokedIndefiniteWhitelistStatus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint192", + "name": "indefiniteWhitelistCount", + "type": "uint192" + } + ], + "name": "SetIndefiniteWhitelistStatus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + } + ], + "name": "SetWhitelistExpiration", + "type": "event" + }, + { + "inputs": [], + "name": "INDEFINITE_WHITELISTER_ROLE_DESCRIPTION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlRegistry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "adminRoleDescription", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "address", + "name": "setter", + "type": "address" + } + ], + "name": "airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus", + "outputs": [ + { + "internalType": "bool", + "name": "indefiniteWhitelistStatus", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + } + ], + "name": "airnodeToEndpointIdToRequesterToWhitelistStatus", + "outputs": [ + { + "internalType": "uint64", + "name": "expirationTimestamp", + "type": "uint64" + }, + { + "internalType": "uint192", + "name": "indefiniteWhitelistCount", + "type": "uint192" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + } + ], + "name": "deriveAdminRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "adminRole", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + } + ], + "name": "deriveIndefiniteWhitelisterRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "indefiniteWhitelisterRole", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + } + ], + "name": "deriveWhitelistExpirationExtenderRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "whitelistExpirationExtenderRole", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + } + ], + "name": "deriveWhitelistExpirationSetterRole", + "outputs": [ + { + "internalType": "bytes32", + "name": "whitelistExpirationSetterRole", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "uint64", + "name": "expirationTimestamp", + "type": "uint64" + } + ], + "name": "extendWhitelistExpiration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + } + ], + "name": "isAuthorized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sponsor", + "type": "address" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + } + ], + "name": "isAuthorizedV0", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "address", + "name": "setter", + "type": "address" + } + ], + "name": "revokeIndefiniteWhitelistStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "setIndefiniteWhitelistStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "airnode", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "endpointId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "uint64", + "name": "expirationTimestamp", + "type": "uint64" + } + ], + "name": "setWhitelistExpiration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0xcfcbadbb28e43a0e08392b83deb4c2d57d5b81e4fdb80a1afe9cae605d00153e", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xc97965EbD0f2123Cc31BEc63E18A8Ce9Ef6a1e7e", + "contractAddress": "0x0000000000000000000000000000000000000000", + "transactionIndex": 0, + "gasUsed": "1571034", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x694f84d82d7223dafb1544eb0658f0b83f75684343d5650c7f896dbd2fddcfa3", + "transactionHash": "0xcfcbadbb28e43a0e08392b83deb4c2d57d5b81e4fdb80a1afe9cae605d00153e", + "logs": [], + "blockNumber": 54178449, + "cumulativeGasUsed": "1571034", + "status": 1, + "byzantium": true + }, + "args": ["0x92E5125adF385d86beDb950793526106143b6Df1", "RequesterAuthorizerWithAirnode admin"], + "numDeployments": 1, + "solcInputHash": "d8591a026515856ab7bc7dc284bf2fbe", + "metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_accessControlRegistry\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_adminRoleDescription\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"ExtendedWhitelistExpiration\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"setter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"indefiniteWhitelistCount\",\"type\":\"uint192\"}],\"name\":\"RevokedIndefiniteWhitelistStatus\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"indefiniteWhitelistCount\",\"type\":\"uint192\"}],\"name\":\"SetIndefiniteWhitelistStatus\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"SetWhitelistExpiration\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"INDEFINITE_WHITELISTER_ROLE_DESCRIPTION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"accessControlRegistry\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"adminRoleDescription\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"setter\",\"type\":\"address\"}],\"name\":\"airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"indefiniteWhitelistStatus\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"name\":\"airnodeToEndpointIdToRequesterToWhitelistStatus\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"expirationTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"uint192\",\"name\":\"indefiniteWhitelistCount\",\"type\":\"uint192\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"}],\"name\":\"deriveAdminRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"adminRole\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"}],\"name\":\"deriveIndefiniteWhitelisterRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"indefiniteWhitelisterRole\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"}],\"name\":\"deriveWhitelistExpirationExtenderRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"whitelistExpirationExtenderRole\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"}],\"name\":\"deriveWhitelistExpirationSetterRole\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"whitelistExpirationSetterRole\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"expirationTimestamp\",\"type\":\"uint64\"}],\"name\":\"extendWhitelistExpiration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"name\":\"isAuthorized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sponsor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"name\":\"isAuthorizedV0\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"setter\",\"type\":\"address\"}],\"name\":\"revokeIndefiniteWhitelistStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"setIndefiniteWhitelistStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"airnode\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"endpointId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"expirationTimestamp\",\"type\":\"uint64\"}],\"name\":\"setWhitelistExpiration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(address,bytes32,address,address)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requester\":\"Requester address\",\"setter\":\"Address of the account that has potentially whitelisted `requester` for the `airnode`\\u2013`endpointId` pair indefinitely\"},\"returns\":{\"indefiniteWhitelistStatus\":\"If `setter` has indefinitely whitelisted `requester` for the `airnode`\\u2013`endpointId` pair\"}},\"airnodeToEndpointIdToRequesterToWhitelistStatus(address,bytes32,address)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requester\":\"Requester address\"},\"returns\":{\"expirationTimestamp\":\"Timestamp at which the temporary whitelist will expire\",\"indefiniteWhitelistCount\":\"Number of times `requester` was whitelisted indefinitely for the `airnode`\\u2013`endpointId` pair\"}},\"constructor\":{\"params\":{\"_accessControlRegistry\":\"AccessControlRegistry contract address\",\"_adminRoleDescription\":\"Admin role description\"}},\"deriveAdminRole(address)\":{\"params\":{\"airnode\":\"Airnode address\"},\"returns\":{\"adminRole\":\"Admin role\"}},\"deriveIndefiniteWhitelisterRole(address)\":{\"params\":{\"airnode\":\"Airnode address\"},\"returns\":{\"indefiniteWhitelisterRole\":\"Indefinite whitelister role\"}},\"deriveWhitelistExpirationExtenderRole(address)\":{\"params\":{\"airnode\":\"Airnode address\"},\"returns\":{\"whitelistExpirationExtenderRole\":\"Whitelist expiration extender role\"}},\"deriveWhitelistExpirationSetterRole(address)\":{\"params\":{\"airnode\":\"Airnode address\"},\"returns\":{\"whitelistExpirationSetterRole\":\"Whitelist expiration setter role\"}},\"extendWhitelistExpiration(address,bytes32,address,uint64)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"expirationTimestamp\":\"Timestamp at which the temporary whitelist will expire\",\"requester\":\"Requester address\"}},\"isAuthorized(address,bytes32,address)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requester\":\"Requester address\"},\"returns\":{\"_0\":\"Authorization status of the request\"}},\"isAuthorizedV0(bytes32,address,bytes32,address,address)\":{\"details\":\"This method has redundant arguments because V0 authorizer contracts have to have the same interface and potential authorizer contracts may require to access the arguments that are redundant here\",\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requestId\":\"Request ID\",\"requester\":\"Requester address\",\"sponsor\":\"Sponsor address\"},\"returns\":{\"_0\":\"Authorization status of the request\"}},\"multicall(bytes[])\":{\"details\":\"Receives and executes a batch of function calls on this contract.\"},\"revokeIndefiniteWhitelistStatus(address,bytes32,address,address)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requester\":\"Requester address\",\"setter\":\"Setter of the indefinite whitelist status\"}},\"setIndefiniteWhitelistStatus(address,bytes32,address,bool)\":{\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"requester\":\"Requester address\",\"status\":\"Indefinite whitelist status\"}},\"setWhitelistExpiration(address,bytes32,address,uint64)\":{\"details\":\"Unlike `extendWhitelistExpiration()`, this can hasten expiration\",\"params\":{\"airnode\":\"Airnode address\",\"endpointId\":\"Endpoint ID\",\"expirationTimestamp\":\"Timestamp at which the temporary whitelist will expire\",\"requester\":\"Requester address\"}}},\"title\":\"Authorizer contract that Airnode operators can use to temporarily or indefinitely whitelist requesters for Airnode\\u2013endpoint pairs\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"INDEFINITE_WHITELISTER_ROLE_DESCRIPTION()\":{\"notice\":\"Indefinite whitelister role description\"},\"WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION()\":{\"notice\":\"Whitelist expiration extender role description\"},\"WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION()\":{\"notice\":\"Whitelist expiration setter role description\"},\"accessControlRegistry()\":{\"notice\":\"AccessControlRegistry contract address\"},\"adminRoleDescription()\":{\"notice\":\"Admin role description\"},\"airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(address,bytes32,address,address)\":{\"notice\":\"Returns if an account has indefinitely whitelisted `requester` for the `airnode`\\u2013`endpointId` pair\"},\"airnodeToEndpointIdToRequesterToWhitelistStatus(address,bytes32,address)\":{\"notice\":\"Returns the whitelist status of `requester` for the `airnode`\\u2013`endpointId` pair\"},\"deriveAdminRole(address)\":{\"notice\":\"Derives the admin role for the Airnode\"},\"deriveIndefiniteWhitelisterRole(address)\":{\"notice\":\"Derives the indefinite whitelister role for the Airnode\"},\"deriveWhitelistExpirationExtenderRole(address)\":{\"notice\":\"Derives the whitelist expiration extender role for the Airnode\"},\"deriveWhitelistExpirationSetterRole(address)\":{\"notice\":\"Derives the whitelist expiration setter role for the Airnode\"},\"extendWhitelistExpiration(address,bytes32,address,uint64)\":{\"notice\":\"Extends the expiration of the temporary whitelist of `requester` for the `airnode`\\u2013`endpointId` pair if the sender has the whitelist expiration extender role\"},\"isAuthorized(address,bytes32,address)\":{\"notice\":\"Verifies the authorization status of a request\"},\"isAuthorizedV0(bytes32,address,bytes32,address,address)\":{\"notice\":\"Verifies the authorization status of a request\"},\"revokeIndefiniteWhitelistStatus(address,bytes32,address,address)\":{\"notice\":\"Revokes the indefinite whitelist status granted by a specific account that no longer has the indefinite whitelister role\"},\"setIndefiniteWhitelistStatus(address,bytes32,address,bool)\":{\"notice\":\"Sets the indefinite whitelist status of `requester` for the `airnode`\\u2013`endpointId` pair if the sender has the indefinite whitelister role\"},\"setWhitelistExpiration(address,bytes32,address,uint64)\":{\"notice\":\"Sets the expiration of the temporary whitelist of `requester` for the `airnode`\\u2013`endpointId` pair if the sender has the whitelist expiration setter role\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/authorizers/RequesterAuthorizerWithAirnode.sol\":\"RequesterAuthorizerWithAirnode\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\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 * _Available since v3.1._\\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 `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Multicall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Multicall.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @dev Provides a function to batch together multiple calls in a single external call.\\n *\\n * _Available since v4.1._\\n */\\nabstract contract Multicall {\\n /**\\n * @dev Receives and executes a batch of function calls on this contract.\\n */\\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n results[i] = Address.functionDelegateCall(address(this), data[i]);\\n }\\n return results;\\n }\\n}\\n\",\"keccak256\":\"0x768ccb0d556d2edde43cf5fc16860a936ce91eca96be0cf9e807ffe875f6f516\",\"license\":\"MIT\"},\"contracts/access-control-registry/AccessControlRegistryAdminned.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Multicall.sol\\\";\\nimport \\\"./RoleDeriver.sol\\\";\\nimport \\\"./AccessControlRegistryUser.sol\\\";\\nimport \\\"./interfaces/IAccessControlRegistryAdminned.sol\\\";\\n\\n/// @title Contract to be inherited by contracts whose adminship functionality\\n/// will be implemented using AccessControlRegistry\\ncontract AccessControlRegistryAdminned is\\n Multicall,\\n RoleDeriver,\\n AccessControlRegistryUser,\\n IAccessControlRegistryAdminned\\n{\\n /// @notice Admin role description\\n string public override adminRoleDescription;\\n\\n bytes32 internal immutable adminRoleDescriptionHash;\\n\\n /// @dev Contracts deployed with the same admin role descriptions will have\\n /// the same roles, meaning that granting an account a role will authorize\\n /// it in multiple contracts. Unless you want your deployed contract to\\n /// share the role configuration of another contract, use a unique admin\\n /// role description.\\n /// @param _accessControlRegistry AccessControlRegistry contract address\\n /// @param _adminRoleDescription Admin role description\\n constructor(\\n address _accessControlRegistry,\\n string memory _adminRoleDescription\\n ) AccessControlRegistryUser(_accessControlRegistry) {\\n require(\\n bytes(_adminRoleDescription).length > 0,\\n \\\"Admin role description empty\\\"\\n );\\n adminRoleDescription = _adminRoleDescription;\\n adminRoleDescriptionHash = keccak256(\\n abi.encodePacked(_adminRoleDescription)\\n );\\n }\\n\\n /// @notice Derives the admin role for the specific manager address\\n /// @param manager Manager address\\n /// @return adminRole Admin role\\n function _deriveAdminRole(address manager)\\n internal\\n view\\n returns (bytes32 adminRole)\\n {\\n adminRole = _deriveRole(\\n _deriveRootRole(manager),\\n adminRoleDescriptionHash\\n );\\n }\\n}\\n\",\"keccak256\":\"0xf09ba7f972b6bc37041596f5fd8757192fe1c63009b75752dc6f57b4eb4bb6cd\",\"license\":\"MIT\"},\"contracts/access-control-registry/AccessControlRegistryUser.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/IAccessControlRegistry.sol\\\";\\nimport \\\"./interfaces/IAccessControlRegistryUser.sol\\\";\\n\\n/// @title Contract to be inherited by contracts that will interact with\\n/// AccessControlRegistry\\ncontract AccessControlRegistryUser is IAccessControlRegistryUser {\\n /// @notice AccessControlRegistry contract address\\n address public immutable override accessControlRegistry;\\n\\n /// @param _accessControlRegistry AccessControlRegistry contract address\\n constructor(address _accessControlRegistry) {\\n require(_accessControlRegistry != address(0), \\\"ACR address zero\\\");\\n accessControlRegistry = _accessControlRegistry;\\n }\\n}\\n\",\"keccak256\":\"0x43744b38d8d71226bc8fb80942d5444a50cd1255f3bded0aee390f897d142802\",\"license\":\"MIT\"},\"contracts/access-control-registry/RoleDeriver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @title Contract to be inherited by contracts that will derive\\n/// AccessControlRegistry roles\\n/// @notice If a contract interfaces with AccessControlRegistry and needs to\\n/// derive roles, it should inherit this contract instead of re-implementing\\n/// the logic\\ncontract RoleDeriver {\\n /// @notice Derives the root role of the manager\\n /// @param manager Manager address\\n /// @return rootRole Root role\\n function _deriveRootRole(address manager)\\n internal\\n pure\\n returns (bytes32 rootRole)\\n {\\n rootRole = keccak256(abi.encodePacked(manager));\\n }\\n\\n /// @notice Derives the role using its admin role and description\\n /// @dev This implies that roles adminned by the same role cannot have the\\n /// same description\\n /// @param adminRole Admin role\\n /// @param description Human-readable description of the role\\n /// @return role Role\\n function _deriveRole(bytes32 adminRole, string memory description)\\n internal\\n pure\\n returns (bytes32 role)\\n {\\n role = _deriveRole(adminRole, keccak256(abi.encodePacked(description)));\\n }\\n\\n /// @notice Derives the role using its admin role and description hash\\n /// @dev This implies that roles adminned by the same role cannot have the\\n /// same description\\n /// @param adminRole Admin role\\n /// @param descriptionHash Hash of the human-readable description of the\\n /// role\\n /// @return role Role\\n function _deriveRole(bytes32 adminRole, bytes32 descriptionHash)\\n internal\\n pure\\n returns (bytes32 role)\\n {\\n role = keccak256(abi.encodePacked(adminRole, descriptionHash));\\n }\\n}\\n\",\"keccak256\":\"0x20fe9d6cce9a1e4fe0b5bd8868fabbe6ee9db7fa8154bcf6316005307d63ee04\",\"license\":\"MIT\"},\"contracts/access-control-registry/interfaces/IAccessControlRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/IAccessControl.sol\\\";\\n\\ninterface IAccessControlRegistry is IAccessControl {\\n event InitializedManager(bytes32 indexed rootRole, address indexed manager);\\n\\n event InitializedRole(\\n bytes32 indexed role,\\n bytes32 indexed adminRole,\\n string description,\\n address sender\\n );\\n\\n function initializeManager(address manager) external;\\n\\n function initializeRoleAndGrantToSender(\\n bytes32 adminRole,\\n string calldata description\\n ) external returns (bytes32 role);\\n\\n function deriveRootRole(address manager)\\n external\\n pure\\n returns (bytes32 rootRole);\\n\\n function deriveRole(bytes32 adminRole, string calldata description)\\n external\\n pure\\n returns (bytes32 role);\\n}\\n\",\"keccak256\":\"0x51b6c37b03f81667920dac10d53efc75e403c11348e71311b39a25c9b1cfdf76\",\"license\":\"MIT\"},\"contracts/access-control-registry/interfaces/IAccessControlRegistryAdminned.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControlRegistryUser.sol\\\";\\n\\ninterface IAccessControlRegistryAdminned is IAccessControlRegistryUser {\\n function adminRoleDescription() external view returns (string memory);\\n}\\n\",\"keccak256\":\"0x0f3ad45d6e1a4815cfaff171926ad5352d499a431b041b11adb316f4569bcce4\",\"license\":\"MIT\"},\"contracts/access-control-registry/interfaces/IAccessControlRegistryUser.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IAccessControlRegistryUser {\\n function accessControlRegistry() external view returns (address);\\n}\\n\",\"keccak256\":\"0xce1ceb04823a801ea173fe5140344645295768ff1b4d2ee2969c2f4b362102ca\",\"license\":\"MIT\"},\"contracts/authorizers/RequesterAuthorizer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"../whitelist/Whitelist.sol\\\";\\nimport \\\"./interfaces/IRequesterAuthorizer.sol\\\";\\n\\n/// @title Abstract contract to be inherited by Authorizer contracts that\\n/// temporarily or permanently whitelist requesters for Airnode\\u2013endpoint pairs\\nabstract contract RequesterAuthorizer is Whitelist, IRequesterAuthorizer {\\n /// @notice Extends the expiration of the temporary whitelist of\\n /// `requester` for the `airnode`\\u2013`endpointId` pair and emits an event\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param requester Requester address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function _extendWhitelistExpirationAndEmit(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) internal {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n require(requester != address(0), \\\"Requester address zero\\\");\\n _extendWhitelistExpiration(\\n deriveServiceId(airnode, endpointId),\\n requester,\\n expirationTimestamp\\n );\\n emit ExtendedWhitelistExpiration(\\n airnode,\\n endpointId,\\n requester,\\n msg.sender,\\n expirationTimestamp\\n );\\n }\\n\\n /// @notice Sets the expiration of the temporary whitelist of `requester`\\n /// for the `airnode`\\u2013`endpointId` pair and emits an event\\n /// @dev Unlike `_extendWhitelistExpiration()`, this can hasten expiration\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param requester Requester address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function _setWhitelistExpirationAndEmit(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) internal {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n require(requester != address(0), \\\"Requester address zero\\\");\\n _setWhitelistExpiration(\\n deriveServiceId(airnode, endpointId),\\n requester,\\n expirationTimestamp\\n );\\n emit SetWhitelistExpiration(\\n airnode,\\n endpointId,\\n requester,\\n msg.sender,\\n expirationTimestamp\\n );\\n }\\n\\n /// @notice Sets the indefinite whitelist status of `requester` for the\\n /// `airnode`\\u2013`endpointId` pair and emits an event\\n /// @dev Emits the event even if it does not change the state.\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param requester Requester address\\n /// @param status Indefinite whitelist status\\n function _setIndefiniteWhitelistStatusAndEmit(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n bool status\\n ) internal {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n require(requester != address(0), \\\"Requester address zero\\\");\\n uint192 indefiniteWhitelistCount = _setIndefiniteWhitelistStatus(\\n deriveServiceId(airnode, endpointId),\\n requester,\\n status\\n );\\n emit SetIndefiniteWhitelistStatus(\\n airnode,\\n endpointId,\\n requester,\\n msg.sender,\\n status,\\n indefiniteWhitelistCount\\n );\\n }\\n\\n /// @notice Revokes the indefinite whitelist status granted to `requester`\\n /// for the `airnode`\\u2013`endpointId` pair by a specific account and emits an\\n /// event\\n /// @dev Only emits the event if it changes the state\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\\n /// @param requester Requester address\\n /// @param setter Setter of the indefinite whitelist status\\n function _revokeIndefiniteWhitelistStatusAndEmit(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n address setter\\n ) internal {\\n require(airnode != address(0), \\\"Airnode address zero\\\");\\n require(requester != address(0), \\\"Requester address zero\\\");\\n require(setter != address(0), \\\"Setter address zero\\\");\\n (\\n bool revoked,\\n uint192 indefiniteWhitelistCount\\n ) = _revokeIndefiniteWhitelistStatus(\\n deriveServiceId(airnode, endpointId),\\n requester,\\n setter\\n );\\n if (revoked) {\\n emit RevokedIndefiniteWhitelistStatus(\\n airnode,\\n endpointId,\\n requester,\\n setter,\\n msg.sender,\\n indefiniteWhitelistCount\\n );\\n }\\n }\\n\\n /// @notice Verifies the authorization status of a request\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @return Authorization status of the request\\n function isAuthorized(\\n address airnode,\\n bytes32 endpointId,\\n address requester\\n ) external view override returns (bool) {\\n return\\n userIsWhitelisted(deriveServiceId(airnode, endpointId), requester);\\n }\\n\\n /// @notice Verifies the authorization status of a request\\n /// @dev This method has redundant arguments because V0 authorizer\\n /// contracts have to have the same interface and potential authorizer\\n /// contracts may require to access the arguments that are redundant here\\n /// @param requestId Request ID\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param sponsor Sponsor address\\n /// @param requester Requester address\\n /// @return Authorization status of the request\\n function isAuthorizedV0(\\n bytes32 requestId, // solhint-disable-line no-unused-vars\\n address airnode,\\n bytes32 endpointId,\\n address sponsor, // solhint-disable-line no-unused-vars\\n address requester\\n ) external view override returns (bool) {\\n return\\n userIsWhitelisted(deriveServiceId(airnode, endpointId), requester);\\n }\\n\\n /// @notice Returns the whitelist status of `requester` for the\\n /// `airnode`\\u2013`endpointId` pair\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @return expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n /// @return indefiniteWhitelistCount Number of times `requester` was\\n /// whitelisted indefinitely for the `airnode`\\u2013`endpointId` pair\\n function airnodeToEndpointIdToRequesterToWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester\\n )\\n external\\n view\\n override\\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount)\\n {\\n WhitelistStatus\\n storage whitelistStatus = serviceIdToUserToWhitelistStatus[\\n deriveServiceId(airnode, endpointId)\\n ][requester];\\n expirationTimestamp = whitelistStatus.expirationTimestamp;\\n indefiniteWhitelistCount = whitelistStatus.indefiniteWhitelistCount;\\n }\\n\\n /// @notice Returns if an account has indefinitely whitelisted `requester`\\n /// for the `airnode`\\u2013`endpointId` pair\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @param setter Address of the account that has potentially whitelisted\\n /// `requester` for the `airnode`\\u2013`endpointId` pair indefinitely\\n /// @return indefiniteWhitelistStatus If `setter` has indefinitely\\n /// whitelisted `requester` for the `airnode`\\u2013`endpointId` pair\\n function airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n address setter\\n ) external view override returns (bool indefiniteWhitelistStatus) {\\n indefiniteWhitelistStatus = serviceIdToUserToSetterToIndefiniteWhitelistStatus[\\n deriveServiceId(airnode, endpointId)\\n ][requester][setter];\\n }\\n\\n /// @notice Called privately to derive a service ID out of the Airnode\\n /// address and the endpoint ID\\n /// @dev This is done to re-use the more general Whitelist contract for\\n /// the specific case of Airnode\\u2013endpoint pairs\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @return serviceId Service ID\\n function deriveServiceId(address airnode, bytes32 endpointId)\\n private\\n pure\\n returns (bytes32 serviceId)\\n {\\n serviceId = keccak256(abi.encodePacked(airnode, endpointId));\\n }\\n}\\n\",\"keccak256\":\"0x7b75fda3fd3e3aba6814a3baba32a429cdb0141f40cf5d0f4a0a8bf85171882a\",\"license\":\"MIT\"},\"contracts/authorizers/RequesterAuthorizerWithAirnode.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"../whitelist/WhitelistRolesWithAirnode.sol\\\";\\nimport \\\"./RequesterAuthorizer.sol\\\";\\nimport \\\"./interfaces/IRequesterAuthorizerWithAirnode.sol\\\";\\n\\n/// @title Authorizer contract that Airnode operators can use to temporarily or\\n/// indefinitely whitelist requesters for Airnode\\u2013endpoint pairs\\ncontract RequesterAuthorizerWithAirnode is\\n WhitelistRolesWithAirnode,\\n RequesterAuthorizer,\\n IRequesterAuthorizerWithAirnode\\n{\\n /// @param _accessControlRegistry AccessControlRegistry contract address\\n /// @param _adminRoleDescription Admin role description\\n constructor(\\n address _accessControlRegistry,\\n string memory _adminRoleDescription\\n )\\n WhitelistRolesWithAirnode(_accessControlRegistry, _adminRoleDescription)\\n {}\\n\\n /// @notice Extends the expiration of the temporary whitelist of\\n /// `requester` for the `airnode`\\u2013`endpointId` pair if the sender has the\\n /// whitelist expiration extender role\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function extendWhitelistExpiration(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) external override {\\n require(\\n hasWhitelistExpirationExtenderRoleOrIsAirnode(airnode, msg.sender),\\n \\\"Cannot extend expiration\\\"\\n );\\n _extendWhitelistExpirationAndEmit(\\n airnode,\\n endpointId,\\n requester,\\n expirationTimestamp\\n );\\n }\\n\\n /// @notice Sets the expiration of the temporary whitelist of `requester`\\n /// for the `airnode`\\u2013`endpointId` pair if the sender has the whitelist\\n /// expiration setter role\\n /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function setWhitelistExpiration(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) external override {\\n require(\\n hasWhitelistExpirationSetterRoleOrIsAirnode(airnode, msg.sender),\\n \\\"Cannot set expiration\\\"\\n );\\n _setWhitelistExpirationAndEmit(\\n airnode,\\n endpointId,\\n requester,\\n expirationTimestamp\\n );\\n }\\n\\n /// @notice Sets the indefinite whitelist status of `requester` for the\\n /// `airnode`\\u2013`endpointId` pair if the sender has the indefinite\\n /// whitelister role\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @param status Indefinite whitelist status\\n function setIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n bool status\\n ) external override {\\n require(\\n hasIndefiniteWhitelisterRoleOrIsAirnode(airnode, msg.sender),\\n \\\"Cannot set indefinite status\\\"\\n );\\n _setIndefiniteWhitelistStatusAndEmit(\\n airnode,\\n endpointId,\\n requester,\\n status\\n );\\n }\\n\\n /// @notice Revokes the indefinite whitelist status granted by a specific\\n /// account that no longer has the indefinite whitelister role\\n /// @param airnode Airnode address\\n /// @param endpointId Endpoint ID\\n /// @param requester Requester address\\n /// @param setter Setter of the indefinite whitelist status\\n function revokeIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n address setter\\n ) external override {\\n require(\\n !hasIndefiniteWhitelisterRoleOrIsAirnode(airnode, setter),\\n \\\"setter can set indefinite status\\\"\\n );\\n _revokeIndefiniteWhitelistStatusAndEmit(\\n airnode,\\n endpointId,\\n requester,\\n setter\\n );\\n }\\n}\\n\",\"keccak256\":\"0xe54f7461125993102c504232e5a93bdca77703e95fcb99fcb1ed196e2f5e09d9\",\"license\":\"MIT\"},\"contracts/authorizers/interfaces/IAuthorizerV0.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IAuthorizerV0 {\\n function isAuthorizedV0(\\n bytes32 requestId,\\n address airnode,\\n bytes32 endpointId,\\n address sponsor,\\n address requester\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xa38872f5dead4dfc0c8075c245c10197df1ace09415f2e0d5b46bc8511cc3f6d\",\"license\":\"MIT\"},\"contracts/authorizers/interfaces/IRequesterAuthorizer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAuthorizerV0.sol\\\";\\n\\ninterface IRequesterAuthorizer is IAuthorizerV0 {\\n event ExtendedWhitelistExpiration(\\n address indexed airnode,\\n bytes32 endpointId,\\n address indexed requester,\\n address indexed sender,\\n uint256 expiration\\n );\\n\\n event SetWhitelistExpiration(\\n address indexed airnode,\\n bytes32 endpointId,\\n address indexed requester,\\n address indexed sender,\\n uint256 expiration\\n );\\n\\n event SetIndefiniteWhitelistStatus(\\n address indexed airnode,\\n bytes32 endpointId,\\n address indexed requester,\\n address indexed sender,\\n bool status,\\n uint192 indefiniteWhitelistCount\\n );\\n\\n event RevokedIndefiniteWhitelistStatus(\\n address indexed airnode,\\n bytes32 endpointId,\\n address indexed requester,\\n address indexed setter,\\n address sender,\\n uint192 indefiniteWhitelistCount\\n );\\n\\n function extendWhitelistExpiration(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) external;\\n\\n function setWhitelistExpiration(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n uint64 expirationTimestamp\\n ) external;\\n\\n function setIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n bool status\\n ) external;\\n\\n function revokeIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n address setter\\n ) external;\\n\\n function airnodeToEndpointIdToRequesterToWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester\\n )\\n external\\n view\\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount);\\n\\n function airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(\\n address airnode,\\n bytes32 endpointId,\\n address requester,\\n address setter\\n ) external view returns (bool indefiniteWhitelistStatus);\\n\\n function isAuthorized(\\n address airnode,\\n bytes32 endpointId,\\n address requester\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x2aecb3b19965b47a373e0bd346b8a626878cc7aa8e85a2156741f7154cd4ec60\",\"license\":\"MIT\"},\"contracts/authorizers/interfaces/IRequesterAuthorizerWithAirnode.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../whitelist/interfaces/IWhitelistRolesWithAirnode.sol\\\";\\nimport \\\"./IRequesterAuthorizer.sol\\\";\\n\\ninterface IRequesterAuthorizerWithAirnode is\\n IWhitelistRolesWithAirnode,\\n IRequesterAuthorizer\\n{}\\n\",\"keccak256\":\"0x5ea885c0792ab843a81ed5294e9edec8be0184aa4f84d51b8cdbe297d002b6e6\",\"license\":\"MIT\"},\"contracts/whitelist/Whitelist.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @title Contract to be inherited by contracts that need temporary and\\n/// permanent whitelists for services identified by hashes\\n/// @notice This contract implements two kinds of whitelisting:\\n/// (1) Temporary, ends when the expiration timestamp is in the past\\n/// (2) Indefinite, ends when the indefinite whitelist count is zero\\n/// Multiple senders can indefinitely whitelist/unwhitelist independently. The\\n/// user will be considered whitelisted as long as there is at least one active\\n/// indefinite whitelisting.\\n/// @dev The interface of this contract is not implemented. It should be\\n/// inherited and its functions should be exposed with a sort of an\\n/// authorization scheme.\\ncontract Whitelist {\\n struct WhitelistStatus {\\n uint64 expirationTimestamp;\\n uint192 indefiniteWhitelistCount;\\n }\\n\\n mapping(bytes32 => mapping(address => WhitelistStatus))\\n internal serviceIdToUserToWhitelistStatus;\\n\\n mapping(bytes32 => mapping(address => mapping(address => bool)))\\n internal serviceIdToUserToSetterToIndefiniteWhitelistStatus;\\n\\n /// @notice Extends the expiration of the temporary whitelist of the user\\n /// for the service\\n /// @param serviceId Service ID\\n /// @param user User address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function _extendWhitelistExpiration(\\n bytes32 serviceId,\\n address user,\\n uint64 expirationTimestamp\\n ) internal {\\n require(\\n expirationTimestamp >\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .expirationTimestamp,\\n \\\"Does not extend expiration\\\"\\n );\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .expirationTimestamp = expirationTimestamp;\\n }\\n\\n /// @notice Sets the expiration of the temporary whitelist of the user for\\n /// the service\\n /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration\\n /// @param serviceId Service ID\\n /// @param user User address\\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\\n /// will expire\\n function _setWhitelistExpiration(\\n bytes32 serviceId,\\n address user,\\n uint64 expirationTimestamp\\n ) internal {\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .expirationTimestamp = expirationTimestamp;\\n }\\n\\n /// @notice Sets the indefinite whitelist status of the user for the\\n /// service\\n /// @dev As long as at least there is at least one account that has set the\\n /// indefinite whitelist status of the user for the service as true, the\\n /// user will be considered whitelisted\\n /// @param serviceId Service ID\\n /// @param user User address\\n /// @param status Indefinite whitelist status\\n function _setIndefiniteWhitelistStatus(\\n bytes32 serviceId,\\n address user,\\n bool status\\n ) internal returns (uint192 indefiniteWhitelistCount) {\\n indefiniteWhitelistCount = serviceIdToUserToWhitelistStatus[serviceId][\\n user\\n ].indefiniteWhitelistCount;\\n if (\\n status &&\\n !serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][\\n user\\n ][msg.sender]\\n ) {\\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\\n msg.sender\\n ] = true;\\n indefiniteWhitelistCount++;\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\\n } else if (\\n !status &&\\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\\n msg.sender\\n ]\\n ) {\\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\\n msg.sender\\n ] = false;\\n indefiniteWhitelistCount--;\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\\n }\\n }\\n\\n /// @notice Revokes the indefinite whitelist status granted to the user for\\n /// the service by a specific account\\n /// @param serviceId Service ID\\n /// @param user User address\\n /// @param setter Setter of the indefinite whitelist status\\n function _revokeIndefiniteWhitelistStatus(\\n bytes32 serviceId,\\n address user,\\n address setter\\n ) internal returns (bool revoked, uint192 indefiniteWhitelistCount) {\\n indefiniteWhitelistCount = serviceIdToUserToWhitelistStatus[serviceId][\\n user\\n ].indefiniteWhitelistCount;\\n if (\\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\\n setter\\n ]\\n ) {\\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\\n setter\\n ] = false;\\n indefiniteWhitelistCount--;\\n serviceIdToUserToWhitelistStatus[serviceId][user]\\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\\n revoked = true;\\n }\\n }\\n\\n /// @notice Returns if the user is whitelised to use the service\\n /// @param serviceId Service ID\\n /// @param user User address\\n /// @return isWhitelisted If the user is whitelisted\\n function userIsWhitelisted(bytes32 serviceId, address user)\\n internal\\n view\\n returns (bool isWhitelisted)\\n {\\n WhitelistStatus\\n storage whitelistStatus = serviceIdToUserToWhitelistStatus[\\n serviceId\\n ][user];\\n return\\n whitelistStatus.indefiniteWhitelistCount > 0 ||\\n whitelistStatus.expirationTimestamp > block.timestamp;\\n }\\n}\\n\",\"keccak256\":\"0x22e3980c4144e2f57a115e51b05f1aeede12fe94fbeb538a287f02e9eff6be89\",\"license\":\"MIT\"},\"contracts/whitelist/WhitelistRoles.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/IWhitelistRoles.sol\\\";\\n\\n/// @title Contract to be inherited by Whitelist contracts that will use\\n/// generic AccessControlRegistry roles\\ncontract WhitelistRoles is IWhitelistRoles {\\n // There are four roles implemented in this contract:\\n // Root\\n // \\u2514\\u2500\\u2500 (1) Admin (can grant and revoke the roles below)\\n // \\u251c\\u2500\\u2500 (2) Whitelist expiration extender\\n // \\u251c\\u2500\\u2500 (3) Whitelist expiration setter\\n // \\u2514\\u2500\\u2500 (4) Indefinite whitelister\\n // Their IDs are derived from the descriptions below. Refer to\\n // AccessControlRegistry for more information.\\n // To clarify, the root role of the manager is the admin of (1), while (1)\\n // is the admin of (2), (3) and (4). So (1) is more of a \\\"contract admin\\\",\\n // while the `adminRole` used in AccessControl and AccessControlRegistry\\n // refers to a more general adminship relationship between roles.\\n\\n /// @notice Whitelist expiration extender role description\\n string\\n public constant\\n override WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION =\\n \\\"Whitelist expiration extender\\\";\\n\\n /// @notice Whitelist expiration setter role description\\n string\\n public constant\\n override WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION =\\n \\\"Whitelist expiration setter\\\";\\n\\n /// @notice Indefinite whitelister role description\\n\\n string public constant override INDEFINITE_WHITELISTER_ROLE_DESCRIPTION =\\n \\\"Indefinite whitelister\\\";\\n\\n bytes32\\n internal constant WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH =\\n keccak256(\\n abi.encodePacked(WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION)\\n );\\n\\n bytes32\\n internal constant WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH =\\n keccak256(\\n abi.encodePacked(WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION)\\n );\\n\\n bytes32 internal constant INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH =\\n keccak256(abi.encodePacked(INDEFINITE_WHITELISTER_ROLE_DESCRIPTION));\\n}\\n\",\"keccak256\":\"0x2d52cc38e7cc74630a9e268b527da5f091c4916d5e2f946a0f5f3e8a1a9debc3\",\"license\":\"MIT\"},\"contracts/whitelist/WhitelistRolesWithAirnode.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./WhitelistRoles.sol\\\";\\nimport \\\"../access-control-registry/AccessControlRegistryAdminned.sol\\\";\\nimport \\\"./interfaces/IWhitelistRolesWithAirnode.sol\\\";\\nimport \\\"../access-control-registry/interfaces/IAccessControlRegistry.sol\\\";\\n\\n/// @title Contract to be inherited by Whitelist contracts that will use\\n/// roles where each individual Airnode address is its own manager\\ncontract WhitelistRolesWithAirnode is\\n WhitelistRoles,\\n AccessControlRegistryAdminned,\\n IWhitelistRolesWithAirnode\\n{\\n /// @param _accessControlRegistry AccessControlRegistry contract address\\n /// @param _adminRoleDescription Admin role description\\n constructor(\\n address _accessControlRegistry,\\n string memory _adminRoleDescription\\n )\\n AccessControlRegistryAdminned(\\n _accessControlRegistry,\\n _adminRoleDescription\\n )\\n {}\\n\\n /// @notice Derives the admin role for the Airnode\\n /// @param airnode Airnode address\\n /// @return adminRole Admin role\\n function deriveAdminRole(address airnode)\\n external\\n view\\n override\\n returns (bytes32 adminRole)\\n {\\n adminRole = _deriveAdminRole(airnode);\\n }\\n\\n /// @notice Derives the whitelist expiration extender role for the Airnode\\n /// @param airnode Airnode address\\n /// @return whitelistExpirationExtenderRole Whitelist expiration extender\\n /// role\\n function deriveWhitelistExpirationExtenderRole(address airnode)\\n public\\n view\\n override\\n returns (bytes32 whitelistExpirationExtenderRole)\\n {\\n whitelistExpirationExtenderRole = _deriveRole(\\n _deriveAdminRole(airnode),\\n WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH\\n );\\n }\\n\\n /// @notice Derives the whitelist expiration setter role for the Airnode\\n /// @param airnode Airnode address\\n /// @return whitelistExpirationSetterRole Whitelist expiration setter role\\n function deriveWhitelistExpirationSetterRole(address airnode)\\n public\\n view\\n override\\n returns (bytes32 whitelistExpirationSetterRole)\\n {\\n whitelistExpirationSetterRole = _deriveRole(\\n _deriveAdminRole(airnode),\\n WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH\\n );\\n }\\n\\n /// @notice Derives the indefinite whitelister role for the Airnode\\n /// @param airnode Airnode address\\n /// @return indefiniteWhitelisterRole Indefinite whitelister role\\n function deriveIndefiniteWhitelisterRole(address airnode)\\n public\\n view\\n override\\n returns (bytes32 indefiniteWhitelisterRole)\\n {\\n indefiniteWhitelisterRole = _deriveRole(\\n _deriveAdminRole(airnode),\\n INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH\\n );\\n }\\n\\n /// @dev Returns if the account has the whitelist expiration extender role\\n /// or is the Airnode address\\n /// @param airnode Airnode address\\n /// @param account Account address\\n /// @return If the account has the whitelist extender role or is the\\n /// Airnode address\\n function hasWhitelistExpirationExtenderRoleOrIsAirnode(\\n address airnode,\\n address account\\n ) internal view returns (bool) {\\n return\\n airnode == account ||\\n IAccessControlRegistry(accessControlRegistry).hasRole(\\n deriveWhitelistExpirationExtenderRole(airnode),\\n account\\n );\\n }\\n\\n /// @dev Returns if the account has the whitelist expriation setter role or\\n /// is the Airnode address\\n /// @param airnode Airnode address\\n /// @param account Account address\\n /// @return If the account has the whitelist setter role or is the Airnode\\n /// address\\n function hasWhitelistExpirationSetterRoleOrIsAirnode(\\n address airnode,\\n address account\\n ) internal view returns (bool) {\\n return\\n airnode == account ||\\n IAccessControlRegistry(accessControlRegistry).hasRole(\\n deriveWhitelistExpirationSetterRole(airnode),\\n account\\n );\\n }\\n\\n /// @dev Returns if the account has the indefinite whitelister role or is the\\n /// Airnode address\\n /// @param airnode Airnode address\\n /// @param account Account address\\n /// @return If the account has the indefinite whitelister role or is the\\n /// Airnode addrss\\n function hasIndefiniteWhitelisterRoleOrIsAirnode(\\n address airnode,\\n address account\\n ) internal view returns (bool) {\\n return\\n airnode == account ||\\n IAccessControlRegistry(accessControlRegistry).hasRole(\\n deriveIndefiniteWhitelisterRole(airnode),\\n account\\n );\\n }\\n}\\n\",\"keccak256\":\"0xc6f268bcf4826e93c71352a0d4b7b8adae32895f560d8eba9ba6ed7b0a454e32\",\"license\":\"MIT\"},\"contracts/whitelist/interfaces/IWhitelistRoles.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IWhitelistRoles {\\n // solhint-disable-next-line func-name-mixedcase\\n function WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION()\\n external\\n view\\n returns (string memory);\\n\\n // solhint-disable-next-line func-name-mixedcase\\n function WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION()\\n external\\n view\\n returns (string memory);\\n\\n // solhint-disable-next-line func-name-mixedcase\\n function INDEFINITE_WHITELISTER_ROLE_DESCRIPTION()\\n external\\n view\\n returns (string memory);\\n}\\n\",\"keccak256\":\"0x1143190e909f6aa779e99d143fdb26a91e42d269814a0d76152d31418db39fbf\",\"license\":\"MIT\"},\"contracts/whitelist/interfaces/IWhitelistRolesWithAirnode.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IWhitelistRoles.sol\\\";\\nimport \\\"../../access-control-registry/interfaces/IAccessControlRegistryAdminned.sol\\\";\\n\\ninterface IWhitelistRolesWithAirnode is\\n IWhitelistRoles,\\n IAccessControlRegistryAdminned\\n{\\n function deriveAdminRole(address airnode)\\n external\\n view\\n returns (bytes32 role);\\n\\n function deriveWhitelistExpirationExtenderRole(address airnode)\\n external\\n view\\n returns (bytes32 role);\\n\\n function deriveWhitelistExpirationSetterRole(address airnode)\\n external\\n view\\n returns (bytes32 role);\\n\\n function deriveIndefiniteWhitelisterRole(address airnode)\\n external\\n view\\n returns (bytes32 role);\\n}\\n\",\"keccak256\":\"0x019f362313bde834e12b45eec821ab20e75e6e54b11de7a2df33b39d516e5d09\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60c06040523480156200001157600080fd5b5060405162001d8938038062001d89833981016040819052620000349162000224565b81818181816001600160a01b038116620000885760405162461bcd60e51b815260206004820152601060248201526f4143522061646472657373207a65726f60801b60448201526064015b60405180910390fd5b6001600160a01b03166080528051620000e45760405162461bcd60e51b815260206004820152601c60248201527f41646d696e20726f6c65206465736372697074696f6e20656d7074790000000060448201526064016200007f565b8051620000f990600090602084019062000135565b50806040516020016200010d9190620002ff565b60408051601f19818403018152919052805160209091012060a052506200035a945050505050565b82805462000143906200031d565b90600052602060002090601f016020900481019282620001675760008555620001b2565b82601f106200018257805160ff1916838001178555620001b2565b82800160010185558215620001b2579182015b82811115620001b257825182559160200191906001019062000195565b50620001c0929150620001c4565b5090565b5b80821115620001c05760008155600101620001c5565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200020e578181015183820152602001620001f4565b838111156200021e576000848401525b50505050565b600080604083850312156200023857600080fd5b82516001600160a01b03811681146200025057600080fd5b60208401519092506001600160401b03808211156200026e57600080fd5b818501915085601f8301126200028357600080fd5b815181811115620002985762000298620001db565b604051601f8201601f19908116603f01168101908382118183101715620002c357620002c3620001db565b81604052828152886020848701011115620002dd57600080fd5b620002f0836020830160208801620001f1565b80955050505050509250929050565b6000825162000313818460208701620001f1565b9190910192915050565b600181811c908216806200033257607f821691505b602082108114156200035457634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a0516119f4620003956000396000610d620152600081816101400152818161097801528181610b980152610dbd01526119f46000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80636db798f9116100b25780639caa101b11610081578063b6316d8811610066578063b6316d8814610332578063d55a42dd14610345578063f57a044a1461038157600080fd5b80639caa101b146102ff578063ac9650d81461031257600080fd5b80636db798f91461026257806373c0627e1461029e5780637e766bc1146102b157806382d229e3146102c457600080fd5b80634751c2e2116101095780634cffd606116100ee5780634cffd606146101f257806352300976146102135780636bd2bdd01461022657600080fd5b80634751c2e2146101ca5780634c8f1d8d146101dd57600080fd5b80631ce9ae071461013b578063216de27e1461017f57806329b915b3146101a257806343b64962146101b5575b600080fd5b6101627f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b61019261018d366004611540565b610394565b6040519015158152602001610176565b6101926101b036600461158d565b6103e1565b6101c86101c33660046115f5565b610400565b005b6101c86101d8366004611644565b61046d565b6101e56104cf565b60405161017691906116ed565b610205610200366004611700565b61055d565b604051908152602001610176565b610205610221366004611700565b61056e565b6101e56040518060400160405280601b81526020017f57686974656c6973742065787069726174696f6e20736574746572000000000081525081565b6101e56040518060400160405280601d81526020017f57686974656c6973742065787069726174696f6e20657874656e64657200000081525081565b6101c86102ac366004611644565b6105dd565b6101c86102bf366004611540565b61063f565b6102d76102d236600461171b565b6106a2565b6040805167ffffffffffffffff90931683526001600160c01b03909116602083015201610176565b61020561030d366004611700565b610706565b610325610320366004611757565b61075a565b60405161017691906117cc565b610205610340366004611700565b61084f565b6101e56040518060400160405280601681526020017f496e646566696e6974652077686974656c69737465720000000000000000000081525081565b61019261038f36600461171b565b6108a3565b6000600260006103a487876108bc565b8152602080820192909252604090810160009081206001600160a01b03968716825283528181209490951685529290525090205460ff1692915050565b60006103f66103f086866108bc565b83610904565b9695505050505050565b61040a8433610959565b61045b5760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f742073657420696e646566696e697465207374617475730000000060448201526064015b60405180910390fd5b61046784848484610a44565b50505050565b6104778433610b79565b6104c35760405162461bcd60e51b815260206004820152601560248201527f43616e6e6f74207365742065787069726174696f6e00000000000000000000006044820152606401610452565b61046784848484610bce565b600080546104dc9061182e565b80601f01602080910402602001604051908101604052809291908181526020018280546105089061182e565b80156105555780601f1061052a57610100808354040283529160200191610555565b820191906000526020600020905b81548152906001019060200180831161053857829003601f168201915b505050505081565b600061056882610d18565b92915050565b600061056861057c83610d18565b6040518060400160405280601d81526020017f57686974656c6973742065787069726174696f6e20657874656e6465720000008152506040516020016105c29190611869565b60405160208183030381529060405280519060200120610d82565b6105e78433610d9e565b6106335760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420657874656e642065787069726174696f6e00000000000000006044820152606401610452565b61046784848484610df3565b6106498482610959565b156106965760405162461bcd60e51b815260206004820181905260248201527f7365747465722063616e2073657420696e646566696e697465207374617475736044820152606401610452565b61046784848484610efb565b6000806000600160006106b588886108bc565b8152602080820192909252604090810160009081206001600160a01b03979097168152959091529093205467ffffffffffffffff811696600160401b9091046001600160c01b031695509350505050565b600061056861071483610d18565b6040518060400160405280601681526020017f496e646566696e6974652077686974656c6973746572000000000000000000008152506040516020016105c29190611869565b60608167ffffffffffffffff81111561077557610775611885565b6040519080825280602002602001820160405280156107a857816020015b60608152602001906001900390816107935790505b50905060005b8281101561084857610818308585848181106107cc576107cc61189b565b90506020028101906107de91906118b1565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061107992505050565b82828151811061082a5761082a61189b565b6020026020010181905250808061084090611915565b9150506107ae565b5092915050565b600061056861085d83610d18565b6040518060400160405280601b81526020017f57686974656c6973742065787069726174696f6e2073657474657200000000008152506040516020016105c29190611869565b60006108b26103f085856108bc565b90505b9392505050565b6040516bffffffffffffffffffffffff19606084901b166020820152603481018290526000906054015b60405160208183030381529060405280519060200120905092915050565b60008281526001602090815260408083206001600160a01b038516845290915281208054600160401b90046001600160c01b0316151580610951575080544267ffffffffffffffff909116115b949350505050565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae85610706565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815260048101919091526001600160a01b038516602482015260440160206040518083038186803b158015610a0c57600080fd5b505afa158015610a20573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b59190611930565b6001600160a01b038416610a915760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610ae75760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b6000610afd610af686866108bc565b848461109e565b9050336001600160a01b0316836001600160a01b0316866001600160a01b03167f13d4d6afcb6d196f753a522f275673066719bb13944bd021efd1fca4286df20d878686604051610b6a9392919092835290151560208301526001600160c01b0316604082015260600190565b60405180910390a45050505050565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae8561084f565b6001600160a01b038416610c1b5760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610c715760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b610cbd610c7e85856108bc565b60009081526001602090815260408083206001600160a01b03871684529091529020805467ffffffffffffffff191667ffffffffffffffff8416179055565b6040805184815267ffffffffffffffff8316602082015233916001600160a01b0385811692908816917f375ee45428e158031095010484fd6451af89c501c79d75e390da4e91eb480ce191015b60405180910390a450505050565b6000610568610d60836040516bffffffffffffffffffffffff19606083901b166020820152600090603401604051602081830303815290604052805190602001209050919050565b7f00000000000000000000000000000000000000000000000000000000000000005b60408051602081018490529081018290526000906060016108e6565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae8561056e565b6001600160a01b038416610e405760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610e965760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b610eaa610ea385856108bc565b83836112a2565b6040805184815267ffffffffffffffff8316602082015233916001600160a01b0385811692908816917ff9b174be67f83278d4516865d1b9ba4576b73e523ea0c2f124ea29152bb1b6769101610d0a565b6001600160a01b038416610f485760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610f9e5760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b6001600160a01b038116610ff45760405162461bcd60e51b815260206004820152601360248201527f5365747465722061646472657373207a65726f000000000000000000000000006044820152606401610452565b60008061100b61100487876108bc565b8585611321565b91509150811561107157604080518681523360208201526001600160c01b0383168183015290516001600160a01b038581169287821692918a16917fdca622020d204c36e9588e7be4184758283d992606ab73318776824b44e2859d9181900360600190a45b505050505050565b60606108b583836040518060600160405280602781526020016119986027913961140f565b60008381526001602090815260408083206001600160a01b0386168452909152902054600160401b90046001600160c01b0316818015611109575060008481526002602090815260408083206001600160a01b0387168452825280832033845290915290205460ff16155b156111975760008481526002602090815260408083206001600160a01b038716845282528083203384529091529020805460ff191660011790558061114d8161194d565b60008681526001602090815260408083206001600160a01b03891684529091529020805467ffffffffffffffff16600160401b6001600160c01b0384160217905591506108b59050565b811580156111cf575060008481526002602090815260408083206001600160a01b0387168452825280832033845290915290205460ff165b156108b55760008481526002602090815260408083206001600160a01b038716845282528083203384529091529020805460ff191690558061121081611974565b60008681526001602090815260408083206001600160a01b0389168452909152902080546001600160c01b038316600160401b0267ffffffffffffffff9091161790559150509392505050565b60009283526001602090815260408085206001600160a01b039490941685529290529120805467ffffffffffffffff191667ffffffffffffffff909216919091179055565b60008381526001602090815260408083206001600160a01b038616845290915290205467ffffffffffffffff9081169082161161125d5760405162461bcd60e51b815260206004820152601a60248201527f446f6573206e6f7420657874656e642065787069726174696f6e0000000000006044820152606401610452565b60008381526001602090815260408083206001600160a01b0386811680865291845282852054888652600285528386209286529184528285209086168552909252822054600160401b9091046001600160c01b03169060ff16156114075760008581526002602090815260408083206001600160a01b03808916855290835281842090871684529091529020805460ff19169055806113bf81611974565b60008781526001602081815260408084206001600160a01b038b168552909152909120805467ffffffffffffffff16600160401b6001600160c01b0385160217905593509150505b935093915050565b6060833b6114855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610452565b600080856001600160a01b0316856040516114a09190611869565b600060405180830381855af49150503d80600081146114db576040519150601f19603f3d011682016040523d82523d6000602084013e6114e0565b606091505b50915091506103f6828286606083156114fa5750816108b5565b82511561150a5782518084602001fd5b8160405162461bcd60e51b815260040161045291906116ed565b80356001600160a01b038116811461153b57600080fd5b919050565b6000806000806080858703121561155657600080fd5b61155f85611524565b93506020850135925061157460408601611524565b915061158260608601611524565b905092959194509250565b600080600080600060a086880312156115a557600080fd5b853594506115b560208701611524565b9350604086013592506115ca60608701611524565b91506115d860808701611524565b90509295509295909350565b80151581146115f257600080fd5b50565b6000806000806080858703121561160b57600080fd5b61161485611524565b93506020850135925061162960408601611524565b91506060850135611639816115e4565b939692955090935050565b6000806000806080858703121561165a57600080fd5b61166385611524565b93506020850135925061167860408601611524565b9150606085013567ffffffffffffffff8116811461163957600080fd5b60005b838110156116b0578181015183820152602001611698565b838111156104675750506000910152565b600081518084526116d9816020860160208601611695565b601f01601f19169290920160200192915050565b6020815260006108b560208301846116c1565b60006020828403121561171257600080fd5b6108b582611524565b60008060006060848603121561173057600080fd5b61173984611524565b92506020840135915061174e60408501611524565b90509250925092565b6000806020838503121561176a57600080fd5b823567ffffffffffffffff8082111561178257600080fd5b818501915085601f83011261179657600080fd5b8135818111156117a557600080fd5b8660208260051b85010111156117ba57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561182157603f1988860301845261180f8583516116c1565b945092850192908501906001016117f3565b5092979650505050505050565b600181811c9082168061184257607f821691505b6020821081141561186357634e487b7160e01b600052602260045260246000fd5b50919050565b6000825161187b818460208701611695565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126118c857600080fd5b83018035915067ffffffffffffffff8211156118e357600080fd5b6020019150368190038213156118f857600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415611929576119296118ff565b5060010190565b60006020828403121561194257600080fd5b81516108b5816115e4565b60006001600160c01b038083168181141561196a5761196a6118ff565b6001019392505050565b60006001600160c01b0382168061198d5761198d6118ff565b600019019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122054c83dd126c12b6928fd970d1f434b676ba73e23c3efdfdac1ccc90a37703ce164736f6c63430008090033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101365760003560e01c80636db798f9116100b25780639caa101b11610081578063b6316d8811610066578063b6316d8814610332578063d55a42dd14610345578063f57a044a1461038157600080fd5b80639caa101b146102ff578063ac9650d81461031257600080fd5b80636db798f91461026257806373c0627e1461029e5780637e766bc1146102b157806382d229e3146102c457600080fd5b80634751c2e2116101095780634cffd606116100ee5780634cffd606146101f257806352300976146102135780636bd2bdd01461022657600080fd5b80634751c2e2146101ca5780634c8f1d8d146101dd57600080fd5b80631ce9ae071461013b578063216de27e1461017f57806329b915b3146101a257806343b64962146101b5575b600080fd5b6101627f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b61019261018d366004611540565b610394565b6040519015158152602001610176565b6101926101b036600461158d565b6103e1565b6101c86101c33660046115f5565b610400565b005b6101c86101d8366004611644565b61046d565b6101e56104cf565b60405161017691906116ed565b610205610200366004611700565b61055d565b604051908152602001610176565b610205610221366004611700565b61056e565b6101e56040518060400160405280601b81526020017f57686974656c6973742065787069726174696f6e20736574746572000000000081525081565b6101e56040518060400160405280601d81526020017f57686974656c6973742065787069726174696f6e20657874656e64657200000081525081565b6101c86102ac366004611644565b6105dd565b6101c86102bf366004611540565b61063f565b6102d76102d236600461171b565b6106a2565b6040805167ffffffffffffffff90931683526001600160c01b03909116602083015201610176565b61020561030d366004611700565b610706565b610325610320366004611757565b61075a565b60405161017691906117cc565b610205610340366004611700565b61084f565b6101e56040518060400160405280601681526020017f496e646566696e6974652077686974656c69737465720000000000000000000081525081565b61019261038f36600461171b565b6108a3565b6000600260006103a487876108bc565b8152602080820192909252604090810160009081206001600160a01b03968716825283528181209490951685529290525090205460ff1692915050565b60006103f66103f086866108bc565b83610904565b9695505050505050565b61040a8433610959565b61045b5760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f742073657420696e646566696e697465207374617475730000000060448201526064015b60405180910390fd5b61046784848484610a44565b50505050565b6104778433610b79565b6104c35760405162461bcd60e51b815260206004820152601560248201527f43616e6e6f74207365742065787069726174696f6e00000000000000000000006044820152606401610452565b61046784848484610bce565b600080546104dc9061182e565b80601f01602080910402602001604051908101604052809291908181526020018280546105089061182e565b80156105555780601f1061052a57610100808354040283529160200191610555565b820191906000526020600020905b81548152906001019060200180831161053857829003601f168201915b505050505081565b600061056882610d18565b92915050565b600061056861057c83610d18565b6040518060400160405280601d81526020017f57686974656c6973742065787069726174696f6e20657874656e6465720000008152506040516020016105c29190611869565b60405160208183030381529060405280519060200120610d82565b6105e78433610d9e565b6106335760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420657874656e642065787069726174696f6e00000000000000006044820152606401610452565b61046784848484610df3565b6106498482610959565b156106965760405162461bcd60e51b815260206004820181905260248201527f7365747465722063616e2073657420696e646566696e697465207374617475736044820152606401610452565b61046784848484610efb565b6000806000600160006106b588886108bc565b8152602080820192909252604090810160009081206001600160a01b03979097168152959091529093205467ffffffffffffffff811696600160401b9091046001600160c01b031695509350505050565b600061056861071483610d18565b6040518060400160405280601681526020017f496e646566696e6974652077686974656c6973746572000000000000000000008152506040516020016105c29190611869565b60608167ffffffffffffffff81111561077557610775611885565b6040519080825280602002602001820160405280156107a857816020015b60608152602001906001900390816107935790505b50905060005b8281101561084857610818308585848181106107cc576107cc61189b565b90506020028101906107de91906118b1565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061107992505050565b82828151811061082a5761082a61189b565b6020026020010181905250808061084090611915565b9150506107ae565b5092915050565b600061056861085d83610d18565b6040518060400160405280601b81526020017f57686974656c6973742065787069726174696f6e2073657474657200000000008152506040516020016105c29190611869565b60006108b26103f085856108bc565b90505b9392505050565b6040516bffffffffffffffffffffffff19606084901b166020820152603481018290526000906054015b60405160208183030381529060405280519060200120905092915050565b60008281526001602090815260408083206001600160a01b038516845290915281208054600160401b90046001600160c01b0316151580610951575080544267ffffffffffffffff909116115b949350505050565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae85610706565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815260048101919091526001600160a01b038516602482015260440160206040518083038186803b158015610a0c57600080fd5b505afa158015610a20573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b59190611930565b6001600160a01b038416610a915760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610ae75760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b6000610afd610af686866108bc565b848461109e565b9050336001600160a01b0316836001600160a01b0316866001600160a01b03167f13d4d6afcb6d196f753a522f275673066719bb13944bd021efd1fca4286df20d878686604051610b6a9392919092835290151560208301526001600160c01b0316604082015260600190565b60405180910390a45050505050565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae8561084f565b6001600160a01b038416610c1b5760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610c715760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b610cbd610c7e85856108bc565b60009081526001602090815260408083206001600160a01b03871684529091529020805467ffffffffffffffff191667ffffffffffffffff8416179055565b6040805184815267ffffffffffffffff8316602082015233916001600160a01b0385811692908816917f375ee45428e158031095010484fd6451af89c501c79d75e390da4e91eb480ce191015b60405180910390a450505050565b6000610568610d60836040516bffffffffffffffffffffffff19606083901b166020820152600090603401604051602081830303815290604052805190602001209050919050565b7f00000000000000000000000000000000000000000000000000000000000000005b60408051602081018490529081018290526000906060016108e6565b6000816001600160a01b0316836001600160a01b031614806108b557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148546109ae8561056e565b6001600160a01b038416610e405760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610e965760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b610eaa610ea385856108bc565b83836112a2565b6040805184815267ffffffffffffffff8316602082015233916001600160a01b0385811692908816917ff9b174be67f83278d4516865d1b9ba4576b73e523ea0c2f124ea29152bb1b6769101610d0a565b6001600160a01b038416610f485760405162461bcd60e51b81526020600482015260146024820152734169726e6f64652061646472657373207a65726f60601b6044820152606401610452565b6001600160a01b038216610f9e5760405162461bcd60e51b815260206004820152601660248201527f5265717565737465722061646472657373207a65726f000000000000000000006044820152606401610452565b6001600160a01b038116610ff45760405162461bcd60e51b815260206004820152601360248201527f5365747465722061646472657373207a65726f000000000000000000000000006044820152606401610452565b60008061100b61100487876108bc565b8585611321565b91509150811561107157604080518681523360208201526001600160c01b0383168183015290516001600160a01b038581169287821692918a16917fdca622020d204c36e9588e7be4184758283d992606ab73318776824b44e2859d9181900360600190a45b505050505050565b60606108b583836040518060600160405280602781526020016119986027913961140f565b60008381526001602090815260408083206001600160a01b0386168452909152902054600160401b90046001600160c01b0316818015611109575060008481526002602090815260408083206001600160a01b0387168452825280832033845290915290205460ff16155b156111975760008481526002602090815260408083206001600160a01b038716845282528083203384529091529020805460ff191660011790558061114d8161194d565b60008681526001602090815260408083206001600160a01b03891684529091529020805467ffffffffffffffff16600160401b6001600160c01b0384160217905591506108b59050565b811580156111cf575060008481526002602090815260408083206001600160a01b0387168452825280832033845290915290205460ff165b156108b55760008481526002602090815260408083206001600160a01b038716845282528083203384529091529020805460ff191690558061121081611974565b60008681526001602090815260408083206001600160a01b0389168452909152902080546001600160c01b038316600160401b0267ffffffffffffffff9091161790559150509392505050565b60009283526001602090815260408085206001600160a01b039490941685529290529120805467ffffffffffffffff191667ffffffffffffffff909216919091179055565b60008381526001602090815260408083206001600160a01b038616845290915290205467ffffffffffffffff9081169082161161125d5760405162461bcd60e51b815260206004820152601a60248201527f446f6573206e6f7420657874656e642065787069726174696f6e0000000000006044820152606401610452565b60008381526001602090815260408083206001600160a01b0386811680865291845282852054888652600285528386209286529184528285209086168552909252822054600160401b9091046001600160c01b03169060ff16156114075760008581526002602090815260408083206001600160a01b03808916855290835281842090871684529091529020805460ff19169055806113bf81611974565b60008781526001602081815260408084206001600160a01b038b168552909152909120805467ffffffffffffffff16600160401b6001600160c01b0385160217905593509150505b935093915050565b6060833b6114855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610452565b600080856001600160a01b0316856040516114a09190611869565b600060405180830381855af49150503d80600081146114db576040519150601f19603f3d011682016040523d82523d6000602084013e6114e0565b606091505b50915091506103f6828286606083156114fa5750816108b5565b82511561150a5782518084602001fd5b8160405162461bcd60e51b815260040161045291906116ed565b80356001600160a01b038116811461153b57600080fd5b919050565b6000806000806080858703121561155657600080fd5b61155f85611524565b93506020850135925061157460408601611524565b915061158260608601611524565b905092959194509250565b600080600080600060a086880312156115a557600080fd5b853594506115b560208701611524565b9350604086013592506115ca60608701611524565b91506115d860808701611524565b90509295509295909350565b80151581146115f257600080fd5b50565b6000806000806080858703121561160b57600080fd5b61161485611524565b93506020850135925061162960408601611524565b91506060850135611639816115e4565b939692955090935050565b6000806000806080858703121561165a57600080fd5b61166385611524565b93506020850135925061167860408601611524565b9150606085013567ffffffffffffffff8116811461163957600080fd5b60005b838110156116b0578181015183820152602001611698565b838111156104675750506000910152565b600081518084526116d9816020860160208601611695565b601f01601f19169290920160200192915050565b6020815260006108b560208301846116c1565b60006020828403121561171257600080fd5b6108b582611524565b60008060006060848603121561173057600080fd5b61173984611524565b92506020840135915061174e60408501611524565b90509250925092565b6000806020838503121561176a57600080fd5b823567ffffffffffffffff8082111561178257600080fd5b818501915085601f83011261179657600080fd5b8135818111156117a557600080fd5b8660208260051b85010111156117ba57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561182157603f1988860301845261180f8583516116c1565b945092850192908501906001016117f3565b5092979650505050505050565b600181811c9082168061184257607f821691505b6020821081141561186357634e487b7160e01b600052602260045260246000fd5b50919050565b6000825161187b818460208701611695565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126118c857600080fd5b83018035915067ffffffffffffffff8211156118e357600080fd5b6020019150368190038213156118f857600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415611929576119296118ff565b5060010190565b60006020828403121561194257600080fd5b81516108b5816115e4565b60006001600160c01b038083168181141561196a5761196a6118ff565b6001019392505050565b60006001600160c01b0382168061198d5761198d6118ff565b600019019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122054c83dd126c12b6928fd970d1f434b676ba73e23c3efdfdac1ccc90a37703ce164736f6c63430008090033", + "devdoc": { + "kind": "dev", + "methods": { + "airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(address,bytes32,address,address)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requester": "Requester address", + "setter": "Address of the account that has potentially whitelisted `requester` for the `airnode`–`endpointId` pair indefinitely" + }, + "returns": { + "indefiniteWhitelistStatus": "If `setter` has indefinitely whitelisted `requester` for the `airnode`–`endpointId` pair" + } + }, + "airnodeToEndpointIdToRequesterToWhitelistStatus(address,bytes32,address)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requester": "Requester address" + }, + "returns": { + "expirationTimestamp": "Timestamp at which the temporary whitelist will expire", + "indefiniteWhitelistCount": "Number of times `requester` was whitelisted indefinitely for the `airnode`–`endpointId` pair" + } + }, + "constructor": { + "params": { + "_accessControlRegistry": "AccessControlRegistry contract address", + "_adminRoleDescription": "Admin role description" + } + }, + "deriveAdminRole(address)": { + "params": { + "airnode": "Airnode address" + }, + "returns": { + "adminRole": "Admin role" + } + }, + "deriveIndefiniteWhitelisterRole(address)": { + "params": { + "airnode": "Airnode address" + }, + "returns": { + "indefiniteWhitelisterRole": "Indefinite whitelister role" + } + }, + "deriveWhitelistExpirationExtenderRole(address)": { + "params": { + "airnode": "Airnode address" + }, + "returns": { + "whitelistExpirationExtenderRole": "Whitelist expiration extender role" + } + }, + "deriveWhitelistExpirationSetterRole(address)": { + "params": { + "airnode": "Airnode address" + }, + "returns": { + "whitelistExpirationSetterRole": "Whitelist expiration setter role" + } + }, + "extendWhitelistExpiration(address,bytes32,address,uint64)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "expirationTimestamp": "Timestamp at which the temporary whitelist will expire", + "requester": "Requester address" + } + }, + "isAuthorized(address,bytes32,address)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requester": "Requester address" + }, + "returns": { + "_0": "Authorization status of the request" + } + }, + "isAuthorizedV0(bytes32,address,bytes32,address,address)": { + "details": "This method has redundant arguments because V0 authorizer contracts have to have the same interface and potential authorizer contracts may require to access the arguments that are redundant here", + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requestId": "Request ID", + "requester": "Requester address", + "sponsor": "Sponsor address" + }, + "returns": { + "_0": "Authorization status of the request" + } + }, + "multicall(bytes[])": { + "details": "Receives and executes a batch of function calls on this contract." + }, + "revokeIndefiniteWhitelistStatus(address,bytes32,address,address)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requester": "Requester address", + "setter": "Setter of the indefinite whitelist status" + } + }, + "setIndefiniteWhitelistStatus(address,bytes32,address,bool)": { + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "requester": "Requester address", + "status": "Indefinite whitelist status" + } + }, + "setWhitelistExpiration(address,bytes32,address,uint64)": { + "details": "Unlike `extendWhitelistExpiration()`, this can hasten expiration", + "params": { + "airnode": "Airnode address", + "endpointId": "Endpoint ID", + "expirationTimestamp": "Timestamp at which the temporary whitelist will expire", + "requester": "Requester address" + } + } + }, + "title": "Authorizer contract that Airnode operators can use to temporarily or indefinitely whitelist requesters for Airnode–endpoint pairs", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "INDEFINITE_WHITELISTER_ROLE_DESCRIPTION()": { + "notice": "Indefinite whitelister role description" + }, + "WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION()": { + "notice": "Whitelist expiration extender role description" + }, + "WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION()": { + "notice": "Whitelist expiration setter role description" + }, + "accessControlRegistry()": { + "notice": "AccessControlRegistry contract address" + }, + "adminRoleDescription()": { + "notice": "Admin role description" + }, + "airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(address,bytes32,address,address)": { + "notice": "Returns if an account has indefinitely whitelisted `requester` for the `airnode`–`endpointId` pair" + }, + "airnodeToEndpointIdToRequesterToWhitelistStatus(address,bytes32,address)": { + "notice": "Returns the whitelist status of `requester` for the `airnode`–`endpointId` pair" + }, + "deriveAdminRole(address)": { + "notice": "Derives the admin role for the Airnode" + }, + "deriveIndefiniteWhitelisterRole(address)": { + "notice": "Derives the indefinite whitelister role for the Airnode" + }, + "deriveWhitelistExpirationExtenderRole(address)": { + "notice": "Derives the whitelist expiration extender role for the Airnode" + }, + "deriveWhitelistExpirationSetterRole(address)": { + "notice": "Derives the whitelist expiration setter role for the Airnode" + }, + "extendWhitelistExpiration(address,bytes32,address,uint64)": { + "notice": "Extends the expiration of the temporary whitelist of `requester` for the `airnode`–`endpointId` pair if the sender has the whitelist expiration extender role" + }, + "isAuthorized(address,bytes32,address)": { + "notice": "Verifies the authorization status of a request" + }, + "isAuthorizedV0(bytes32,address,bytes32,address,address)": { + "notice": "Verifies the authorization status of a request" + }, + "revokeIndefiniteWhitelistStatus(address,bytes32,address,address)": { + "notice": "Revokes the indefinite whitelist status granted by a specific account that no longer has the indefinite whitelister role" + }, + "setIndefiniteWhitelistStatus(address,bytes32,address,bool)": { + "notice": "Sets the indefinite whitelist status of `requester` for the `airnode`–`endpointId` pair if the sender has the indefinite whitelister role" + }, + "setWhitelistExpiration(address,bytes32,address,uint64)": { + "notice": "Sets the expiration of the temporary whitelist of `requester` for the `airnode`–`endpointId` pair if the sender has the whitelist expiration setter role" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 1697, + "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", + "label": "adminRoleDescription", + "offset": 0, + "slot": "0", + "type": "t_string_storage" + }, + { + "astId": 5218, + "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", + "label": "serviceIdToUserToWhitelistStatus", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_struct(WhitelistStatus)5211_storage))" + }, + { + "astId": 5226, + "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", + "label": "serviceIdToUserToSetterToIndefiniteWhitelistStatus", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_mapping(t_address,t_bool)))" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_mapping(t_address,t_bool))": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => mapping(address => bool))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_bool)" + }, + "t_mapping(t_address,t_struct(WhitelistStatus)5211_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct Whitelist.WhitelistStatus)", + "numberOfBytes": "32", + "value": "t_struct(WhitelistStatus)5211_storage" + }, + "t_mapping(t_bytes32,t_mapping(t_address,t_mapping(t_address,t_bool)))": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => mapping(address => mapping(address => bool)))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_mapping(t_address,t_bool))" + }, + "t_mapping(t_bytes32,t_mapping(t_address,t_struct(WhitelistStatus)5211_storage))": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => mapping(address => struct Whitelist.WhitelistStatus))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_struct(WhitelistStatus)5211_storage)" + }, + "t_string_storage": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(WhitelistStatus)5211_storage": { + "encoding": "inplace", + "label": "struct Whitelist.WhitelistStatus", + "members": [ + { + "astId": 5208, + "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", + "label": "expirationTimestamp", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 5210, + "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", + "label": "indefiniteWhitelistCount", + "offset": 8, + "slot": "0", + "type": "t_uint192" + } + ], + "numberOfBytes": "32" + }, + "t_uint192": { + "encoding": "inplace", + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint64": { + "encoding": "inplace", + "label": "uint64", + "numberOfBytes": "8" + } + } + } +} diff --git a/packages/airnode-protocol/deployments/lightlink/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json b/packages/airnode-protocol/deployments/lightlink/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json new file mode 100644 index 0000000000..d38c4a14fa --- /dev/null +++ b/packages/airnode-protocol/deployments/lightlink/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json @@ -0,0 +1,189 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../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 * ```\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 * ```\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.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => 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 a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role, _msgSender());\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 override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(uint160(account), 20),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\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 override 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 function grantRole(bytes32 role, address account) public virtual override 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 function revokeRole(bytes32 role, address account) public virtual override 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 `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\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 Grants `role` to `account`.\n *\n * Internal function without access restriction.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\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 * _Available since v3.1._\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 `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize, which returns 0 for contracts in\n // construction, since the code is only stored at the end of the\n // constructor execution.\n\n uint256 size;\n assembly {\n size := extcodesize(account)\n }\n return size > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\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" + }, + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s;\n uint8 v;\n assembly {\n s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\n v := add(shr(255, vs), 27)\n }\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./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 *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override 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 v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\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" + }, + "@openzeppelin/contracts/utils/Multicall.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Multicall.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./Address.sol\";\n\n/**\n * @dev Provides a function to batch together multiple calls in a single external call.\n *\n * _Available since v4.1._\n */\nabstract contract Multicall {\n /**\n * @dev Receives and executes a batch of function calls on this contract.\n */\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n results[i] = Address.functionDelegateCall(address(this), data[i]);\n }\n return results;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "contracts/access-control-registry/AccessControlRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"@openzeppelin/contracts/utils/Multicall.sol\";\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"./RoleDeriver.sol\";\nimport \"./interfaces/IAccessControlRegistry.sol\";\n\n/// @title Contract that allows users to manage independent, tree-shaped access\n/// control tables\n/// @notice Multiple contracts can refer to this contract to check if their\n/// users have granted accounts specific roles. Therefore, it aims to keep all\n/// access control roles of its users in this single contract.\n/// @dev Each user is called a \"manager\", and is the only member of their root\n/// role. Starting from this root role, they can create an arbitrary tree of\n/// roles and grant these to accounts. Each role has a description, and roles\n/// adminned by the same role cannot have the same description.\ncontract AccessControlRegistry is\n Multicall,\n AccessControl,\n RoleDeriver,\n IAccessControlRegistry\n{\n /// @notice Initializes the manager by initializing its root role and\n /// granting it to them\n /// @dev Anyone can initialize a manager. An uninitialized manager\n /// attempting to initialize a role will be initialized automatically.\n /// Once a manager is initialized, subsequent initializations have no\n /// effect.\n /// @param manager Manager address to be initialized\n function initializeManager(address manager) public override {\n require(manager != address(0), \"Manager address zero\");\n bytes32 rootRole = deriveRootRole(manager);\n if (!hasRole(rootRole, manager)) {\n _grantRole(rootRole, manager);\n emit InitializedManager(rootRole, manager);\n }\n }\n\n /// @notice Called by the account to renounce the role\n /// @dev Overriden to disallow managers to renounce their root roles.\n /// `role` and `account` are not validated because\n /// `AccessControl.renounceRole` will revert if either of them is zero.\n /// @param role Role to be renounced\n /// @param account Account to renounce the role\n function renounceRole(bytes32 role, address account)\n public\n override(AccessControl, IAccessControl)\n {\n require(\n role != deriveRootRole(account),\n \"role is root role of account\"\n );\n AccessControl.renounceRole(role, account);\n }\n\n /// @notice Initializes a role by setting its admin role and grants it to\n /// the sender\n /// @dev If the sender should not have the initialized role, they should\n /// explicitly renounce it after initializing it.\n /// Once a role is initialized, subsequent initializations have no effect\n /// other than granting the role to the sender.\n /// The sender must be a member of `adminRole`. `adminRole` value is not\n /// validated because the sender cannot have the `bytes32(0)` role.\n /// If the sender is an uninitialized manager that is initializing a role\n /// directly under their root role, manager initialization will happen\n /// automatically, which will grant the sender `adminRole` and allow them\n /// to initialize the role.\n /// @param adminRole Admin role to be assigned to the initialized role\n /// @param description Human-readable description of the initialized role\n /// @return role Initialized role\n function initializeRoleAndGrantToSender(\n bytes32 adminRole,\n string calldata description\n ) external override returns (bytes32 role) {\n require(bytes(description).length > 0, \"Role description empty\");\n role = deriveRole(adminRole, description);\n // AccessControl roles have `DEFAULT_ADMIN_ROLE` (i.e., `bytes32(0)`)\n // as their `adminRole` by default. No account in AccessControlRegistry\n // can possibly have that role, which means all initialized roles will\n // have non-default admin roles, and vice versa.\n if (getRoleAdmin(role) == DEFAULT_ADMIN_ROLE) {\n if (adminRole == deriveRootRole(_msgSender())) {\n initializeManager(_msgSender());\n }\n _setRoleAdmin(role, adminRole);\n emit InitializedRole(role, adminRole, description, _msgSender());\n }\n grantRole(role, _msgSender());\n }\n\n /// @notice Derives the root role of the manager\n /// @param manager Manager address\n /// @return rootRole Root role\n function deriveRootRole(address manager)\n public\n pure\n override\n returns (bytes32 rootRole)\n {\n rootRole = _deriveRootRole(manager);\n }\n\n /// @notice Derives the role using its admin role and description\n /// @dev This implies that roles adminned by the same role cannot have the\n /// same description\n /// @param adminRole Admin role\n /// @param description Human-readable description of the role\n /// @return role Role\n function deriveRole(bytes32 adminRole, string calldata description)\n public\n pure\n override\n returns (bytes32 role)\n {\n role = _deriveRole(adminRole, description);\n }\n}\n" + }, + "contracts/access-control-registry/AccessControlRegistryAdminned.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Multicall.sol\";\nimport \"./RoleDeriver.sol\";\nimport \"./AccessControlRegistryUser.sol\";\nimport \"./interfaces/IAccessControlRegistryAdminned.sol\";\n\n/// @title Contract to be inherited by contracts whose adminship functionality\n/// will be implemented using AccessControlRegistry\ncontract AccessControlRegistryAdminned is\n Multicall,\n RoleDeriver,\n AccessControlRegistryUser,\n IAccessControlRegistryAdminned\n{\n /// @notice Admin role description\n string public override adminRoleDescription;\n\n bytes32 internal immutable adminRoleDescriptionHash;\n\n /// @dev Contracts deployed with the same admin role descriptions will have\n /// the same roles, meaning that granting an account a role will authorize\n /// it in multiple contracts. Unless you want your deployed contract to\n /// share the role configuration of another contract, use a unique admin\n /// role description.\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription\n ) AccessControlRegistryUser(_accessControlRegistry) {\n require(\n bytes(_adminRoleDescription).length > 0,\n \"Admin role description empty\"\n );\n adminRoleDescription = _adminRoleDescription;\n adminRoleDescriptionHash = keccak256(\n abi.encodePacked(_adminRoleDescription)\n );\n }\n\n /// @notice Derives the admin role for the specific manager address\n /// @param manager Manager address\n /// @return adminRole Admin role\n function _deriveAdminRole(address manager)\n internal\n view\n returns (bytes32 adminRole)\n {\n adminRole = _deriveRole(\n _deriveRootRole(manager),\n adminRoleDescriptionHash\n );\n }\n}\n" + }, + "contracts/access-control-registry/AccessControlRegistryAdminnedWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./AccessControlRegistryAdminned.sol\";\nimport \"./interfaces/IAccessControlRegistryAdminnedWithManager.sol\";\n\n/// @title Contract to be inherited by contracts with manager whose adminship\n/// functionality will be implemented using AccessControlRegistry\n/// @notice The manager address here is expected to belong to an\n/// AccessControlRegistry user that is a multisig/DAO\ncontract AccessControlRegistryAdminnedWithManager is\n AccessControlRegistryAdminned,\n IAccessControlRegistryAdminnedWithManager\n{\n /// @notice Address of the manager that manages the related\n /// AccessControlRegistry roles\n /// @dev The mutability of the manager role can be implemented by\n /// designating an OwnableCallForwarder contract as the manager. The\n /// ownership of this contract can then be transferred, effectively\n /// transferring managership.\n address public immutable override manager;\n\n /// @notice Admin role\n /// @dev Since `manager` is immutable, so is `adminRole`\n bytes32 public immutable override adminRole;\n\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n /// @param _manager Manager address\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription,\n address _manager\n )\n AccessControlRegistryAdminned(\n _accessControlRegistry,\n _adminRoleDescription\n )\n {\n require(_manager != address(0), \"Manager address zero\");\n manager = _manager;\n adminRole = _deriveAdminRole(_manager);\n }\n}\n" + }, + "contracts/access-control-registry/AccessControlRegistryUser.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interfaces/IAccessControlRegistry.sol\";\nimport \"./interfaces/IAccessControlRegistryUser.sol\";\n\n/// @title Contract to be inherited by contracts that will interact with\n/// AccessControlRegistry\ncontract AccessControlRegistryUser is IAccessControlRegistryUser {\n /// @notice AccessControlRegistry contract address\n address public immutable override accessControlRegistry;\n\n /// @param _accessControlRegistry AccessControlRegistry contract address\n constructor(address _accessControlRegistry) {\n require(_accessControlRegistry != address(0), \"ACR address zero\");\n accessControlRegistry = _accessControlRegistry;\n }\n}\n" + }, + "contracts/access-control-registry/interfaces/IAccessControlRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\ninterface IAccessControlRegistry is IAccessControl {\n event InitializedManager(bytes32 indexed rootRole, address indexed manager);\n\n event InitializedRole(\n bytes32 indexed role,\n bytes32 indexed adminRole,\n string description,\n address sender\n );\n\n function initializeManager(address manager) external;\n\n function initializeRoleAndGrantToSender(\n bytes32 adminRole,\n string calldata description\n ) external returns (bytes32 role);\n\n function deriveRootRole(address manager)\n external\n pure\n returns (bytes32 rootRole);\n\n function deriveRole(bytes32 adminRole, string calldata description)\n external\n pure\n returns (bytes32 role);\n}\n" + }, + "contracts/access-control-registry/interfaces/IAccessControlRegistryAdminned.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlRegistryUser.sol\";\n\ninterface IAccessControlRegistryAdminned is IAccessControlRegistryUser {\n function adminRoleDescription() external view returns (string memory);\n}\n" + }, + "contracts/access-control-registry/interfaces/IAccessControlRegistryAdminnedWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlRegistryAdminned.sol\";\n\ninterface IAccessControlRegistryAdminnedWithManager is\n IAccessControlRegistryAdminned\n{\n function manager() external view returns (address);\n\n function adminRole() external view returns (bytes32);\n}\n" + }, + "contracts/access-control-registry/interfaces/IAccessControlRegistryUser.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IAccessControlRegistryUser {\n function accessControlRegistry() external view returns (address);\n}\n" + }, + "contracts/access-control-registry/RoleDeriver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Contract to be inherited by contracts that will derive\n/// AccessControlRegistry roles\n/// @notice If a contract interfaces with AccessControlRegistry and needs to\n/// derive roles, it should inherit this contract instead of re-implementing\n/// the logic\ncontract RoleDeriver {\n /// @notice Derives the root role of the manager\n /// @param manager Manager address\n /// @return rootRole Root role\n function _deriveRootRole(address manager)\n internal\n pure\n returns (bytes32 rootRole)\n {\n rootRole = keccak256(abi.encodePacked(manager));\n }\n\n /// @notice Derives the role using its admin role and description\n /// @dev This implies that roles adminned by the same role cannot have the\n /// same description\n /// @param adminRole Admin role\n /// @param description Human-readable description of the role\n /// @return role Role\n function _deriveRole(bytes32 adminRole, string memory description)\n internal\n pure\n returns (bytes32 role)\n {\n role = _deriveRole(adminRole, keccak256(abi.encodePacked(description)));\n }\n\n /// @notice Derives the role using its admin role and description hash\n /// @dev This implies that roles adminned by the same role cannot have the\n /// same description\n /// @param adminRole Admin role\n /// @param descriptionHash Hash of the human-readable description of the\n /// role\n /// @return role Role\n function _deriveRole(bytes32 adminRole, bytes32 descriptionHash)\n internal\n pure\n returns (bytes32 role)\n {\n role = keccak256(abi.encodePacked(adminRole, descriptionHash));\n }\n}\n" + }, + "contracts/authorizers/interfaces/IAuthorizerV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IAuthorizerV0 {\n function isAuthorizedV0(\n bytes32 requestId,\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address requester\n ) external view returns (bool);\n}\n" + }, + "contracts/authorizers/interfaces/IRequesterAuthorizer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IAuthorizerV0.sol\";\n\ninterface IRequesterAuthorizer is IAuthorizerV0 {\n event ExtendedWhitelistExpiration(\n address indexed airnode,\n bytes32 endpointId,\n address indexed requester,\n address indexed sender,\n uint256 expiration\n );\n\n event SetWhitelistExpiration(\n address indexed airnode,\n bytes32 endpointId,\n address indexed requester,\n address indexed sender,\n uint256 expiration\n );\n\n event SetIndefiniteWhitelistStatus(\n address indexed airnode,\n bytes32 endpointId,\n address indexed requester,\n address indexed sender,\n bool status,\n uint192 indefiniteWhitelistCount\n );\n\n event RevokedIndefiniteWhitelistStatus(\n address indexed airnode,\n bytes32 endpointId,\n address indexed requester,\n address indexed setter,\n address sender,\n uint192 indefiniteWhitelistCount\n );\n\n function extendWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external;\n\n function setWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external;\n\n function setIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n bool status\n ) external;\n\n function revokeIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) external;\n\n function airnodeToEndpointIdToRequesterToWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester\n )\n external\n view\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount);\n\n function airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) external view returns (bool indefiniteWhitelistStatus);\n\n function isAuthorized(\n address airnode,\n bytes32 endpointId,\n address requester\n ) external view returns (bool);\n}\n" + }, + "contracts/authorizers/interfaces/IRequesterAuthorizerWithAirnode.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../whitelist/interfaces/IWhitelistRolesWithAirnode.sol\";\nimport \"./IRequesterAuthorizer.sol\";\n\ninterface IRequesterAuthorizerWithAirnode is\n IWhitelistRolesWithAirnode,\n IRequesterAuthorizer\n{}\n" + }, + "contracts/authorizers/interfaces/IRequesterAuthorizerWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../whitelist/interfaces/IWhitelistRolesWithManager.sol\";\nimport \"./IRequesterAuthorizer.sol\";\n\ninterface IRequesterAuthorizerWithManager is\n IWhitelistRolesWithManager,\n IRequesterAuthorizer\n{}\n" + }, + "contracts/authorizers/mock/MockAuthorizerAlwaysFalseV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../interfaces/IAuthorizerV0.sol\";\n\n/// @title A mock authorizer that always returns false\ncontract MockAuthorizerAlwaysFalseV0 is IAuthorizerV0 {\n function isAuthorizedV0(\n bytes32 requestId, // solhint-disable-line\n address airnode, // solhint-disable-line\n bytes32 endpointId, // solhint-disable-line\n address sponsor, // solhint-disable-line\n address requester // solhint-disable-line\n ) external view virtual override returns (bool status) {\n status = false;\n }\n}\n" + }, + "contracts/authorizers/mock/MockAuthorizerAlwaysTrueV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../interfaces/IAuthorizerV0.sol\";\n\n/// @title A mock authorizer that always returns true\ncontract MockAuthorizerAlwaysTrueV0 is IAuthorizerV0 {\n function isAuthorizedV0(\n bytes32 requestId, // solhint-disable-line\n address airnode, // solhint-disable-line\n bytes32 endpointId, // solhint-disable-line\n address sponsor, // solhint-disable-line\n address requester // solhint-disable-line\n ) external view virtual override returns (bool status) {\n status = true;\n }\n}\n" + }, + "contracts/authorizers/RequesterAuthorizer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../whitelist/Whitelist.sol\";\nimport \"./interfaces/IRequesterAuthorizer.sol\";\n\n/// @title Abstract contract to be inherited by Authorizer contracts that\n/// temporarily or permanently whitelist requesters for Airnode–endpoint pairs\nabstract contract RequesterAuthorizer is Whitelist, IRequesterAuthorizer {\n /// @notice Extends the expiration of the temporary whitelist of\n /// `requester` for the `airnode`–`endpointId` pair and emits an event\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function _extendWhitelistExpirationAndEmit(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) internal {\n require(airnode != address(0), \"Airnode address zero\");\n require(requester != address(0), \"Requester address zero\");\n _extendWhitelistExpiration(\n deriveServiceId(airnode, endpointId),\n requester,\n expirationTimestamp\n );\n emit ExtendedWhitelistExpiration(\n airnode,\n endpointId,\n requester,\n msg.sender,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the expiration of the temporary whitelist of `requester`\n /// for the `airnode`–`endpointId` pair and emits an event\n /// @dev Unlike `_extendWhitelistExpiration()`, this can hasten expiration\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function _setWhitelistExpirationAndEmit(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) internal {\n require(airnode != address(0), \"Airnode address zero\");\n require(requester != address(0), \"Requester address zero\");\n _setWhitelistExpiration(\n deriveServiceId(airnode, endpointId),\n requester,\n expirationTimestamp\n );\n emit SetWhitelistExpiration(\n airnode,\n endpointId,\n requester,\n msg.sender,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the indefinite whitelist status of `requester` for the\n /// `airnode`–`endpointId` pair and emits an event\n /// @dev Emits the event even if it does not change the state.\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param requester Requester address\n /// @param status Indefinite whitelist status\n function _setIndefiniteWhitelistStatusAndEmit(\n address airnode,\n bytes32 endpointId,\n address requester,\n bool status\n ) internal {\n require(airnode != address(0), \"Airnode address zero\");\n require(requester != address(0), \"Requester address zero\");\n uint192 indefiniteWhitelistCount = _setIndefiniteWhitelistStatus(\n deriveServiceId(airnode, endpointId),\n requester,\n status\n );\n emit SetIndefiniteWhitelistStatus(\n airnode,\n endpointId,\n requester,\n msg.sender,\n status,\n indefiniteWhitelistCount\n );\n }\n\n /// @notice Revokes the indefinite whitelist status granted to `requester`\n /// for the `airnode`–`endpointId` pair by a specific account and emits an\n /// event\n /// @dev Only emits the event if it changes the state\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param requester Requester address\n /// @param setter Setter of the indefinite whitelist status\n function _revokeIndefiniteWhitelistStatusAndEmit(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) internal {\n require(airnode != address(0), \"Airnode address zero\");\n require(requester != address(0), \"Requester address zero\");\n require(setter != address(0), \"Setter address zero\");\n (\n bool revoked,\n uint192 indefiniteWhitelistCount\n ) = _revokeIndefiniteWhitelistStatus(\n deriveServiceId(airnode, endpointId),\n requester,\n setter\n );\n if (revoked) {\n emit RevokedIndefiniteWhitelistStatus(\n airnode,\n endpointId,\n requester,\n setter,\n msg.sender,\n indefiniteWhitelistCount\n );\n }\n }\n\n /// @notice Verifies the authorization status of a request\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @return Authorization status of the request\n function isAuthorized(\n address airnode,\n bytes32 endpointId,\n address requester\n ) external view override returns (bool) {\n return\n userIsWhitelisted(deriveServiceId(airnode, endpointId), requester);\n }\n\n /// @notice Verifies the authorization status of a request\n /// @dev This method has redundant arguments because V0 authorizer\n /// contracts have to have the same interface and potential authorizer\n /// contracts may require to access the arguments that are redundant here\n /// @param requestId Request ID\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param requester Requester address\n /// @return Authorization status of the request\n function isAuthorizedV0(\n bytes32 requestId, // solhint-disable-line no-unused-vars\n address airnode,\n bytes32 endpointId,\n address sponsor, // solhint-disable-line no-unused-vars\n address requester\n ) external view override returns (bool) {\n return\n userIsWhitelisted(deriveServiceId(airnode, endpointId), requester);\n }\n\n /// @notice Returns the whitelist status of `requester` for the\n /// `airnode`–`endpointId` pair\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @return expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n /// @return indefiniteWhitelistCount Number of times `requester` was\n /// whitelisted indefinitely for the `airnode`–`endpointId` pair\n function airnodeToEndpointIdToRequesterToWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester\n )\n external\n view\n override\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount)\n {\n WhitelistStatus\n storage whitelistStatus = serviceIdToUserToWhitelistStatus[\n deriveServiceId(airnode, endpointId)\n ][requester];\n expirationTimestamp = whitelistStatus.expirationTimestamp;\n indefiniteWhitelistCount = whitelistStatus.indefiniteWhitelistCount;\n }\n\n /// @notice Returns if an account has indefinitely whitelisted `requester`\n /// for the `airnode`–`endpointId` pair\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param setter Address of the account that has potentially whitelisted\n /// `requester` for the `airnode`–`endpointId` pair indefinitely\n /// @return indefiniteWhitelistStatus If `setter` has indefinitely\n /// whitelisted `requester` for the `airnode`–`endpointId` pair\n function airnodeToEndpointIdToRequesterToSetterToIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) external view override returns (bool indefiniteWhitelistStatus) {\n indefiniteWhitelistStatus = serviceIdToUserToSetterToIndefiniteWhitelistStatus[\n deriveServiceId(airnode, endpointId)\n ][requester][setter];\n }\n\n /// @notice Called privately to derive a service ID out of the Airnode\n /// address and the endpoint ID\n /// @dev This is done to re-use the more general Whitelist contract for\n /// the specific case of Airnode–endpoint pairs\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @return serviceId Service ID\n function deriveServiceId(address airnode, bytes32 endpointId)\n private\n pure\n returns (bytes32 serviceId)\n {\n serviceId = keccak256(abi.encodePacked(airnode, endpointId));\n }\n}\n" + }, + "contracts/authorizers/RequesterAuthorizerWithAirnode.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../whitelist/WhitelistRolesWithAirnode.sol\";\nimport \"./RequesterAuthorizer.sol\";\nimport \"./interfaces/IRequesterAuthorizerWithAirnode.sol\";\n\n/// @title Authorizer contract that Airnode operators can use to temporarily or\n/// indefinitely whitelist requesters for Airnode–endpoint pairs\ncontract RequesterAuthorizerWithAirnode is\n WhitelistRolesWithAirnode,\n RequesterAuthorizer,\n IRequesterAuthorizerWithAirnode\n{\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription\n )\n WhitelistRolesWithAirnode(_accessControlRegistry, _adminRoleDescription)\n {}\n\n /// @notice Extends the expiration of the temporary whitelist of\n /// `requester` for the `airnode`–`endpointId` pair if the sender has the\n /// whitelist expiration extender role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function extendWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationExtenderRoleOrIsAirnode(airnode, msg.sender),\n \"Cannot extend expiration\"\n );\n _extendWhitelistExpirationAndEmit(\n airnode,\n endpointId,\n requester,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the expiration of the temporary whitelist of `requester`\n /// for the `airnode`–`endpointId` pair if the sender has the whitelist\n /// expiration setter role\n /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function setWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationSetterRoleOrIsAirnode(airnode, msg.sender),\n \"Cannot set expiration\"\n );\n _setWhitelistExpirationAndEmit(\n airnode,\n endpointId,\n requester,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the indefinite whitelist status of `requester` for the\n /// `airnode`–`endpointId` pair if the sender has the indefinite\n /// whitelister role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param status Indefinite whitelist status\n function setIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n bool status\n ) external override {\n require(\n hasIndefiniteWhitelisterRoleOrIsAirnode(airnode, msg.sender),\n \"Cannot set indefinite status\"\n );\n _setIndefiniteWhitelistStatusAndEmit(\n airnode,\n endpointId,\n requester,\n status\n );\n }\n\n /// @notice Revokes the indefinite whitelist status granted by a specific\n /// account that no longer has the indefinite whitelister role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param setter Setter of the indefinite whitelist status\n function revokeIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) external override {\n require(\n !hasIndefiniteWhitelisterRoleOrIsAirnode(airnode, setter),\n \"setter can set indefinite status\"\n );\n _revokeIndefiniteWhitelistStatusAndEmit(\n airnode,\n endpointId,\n requester,\n setter\n );\n }\n}\n" + }, + "contracts/authorizers/RequesterAuthorizerWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../whitelist/WhitelistRolesWithManager.sol\";\nimport \"./RequesterAuthorizer.sol\";\nimport \"./interfaces/IRequesterAuthorizerWithManager.sol\";\n\n/// @title Authorizer contract that a manager can use to temporarily or\n/// indefinitely whitelist requesters for Airnode–endpoint pairs\ncontract RequesterAuthorizerWithManager is\n WhitelistRolesWithManager,\n RequesterAuthorizer,\n IRequesterAuthorizerWithManager\n{\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n /// @param _manager Manager address\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription,\n address _manager\n )\n WhitelistRolesWithManager(\n _accessControlRegistry,\n _adminRoleDescription,\n _manager\n )\n {}\n\n /// @notice Extends the expiration of the temporary whitelist of\n /// `requester` for the `airnode`–`endpointId` pair if the sender has the\n /// whitelist expiration extender role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function extendWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationExtenderRoleOrIsManager(msg.sender),\n \"Cannot extend expiration\"\n );\n _extendWhitelistExpirationAndEmit(\n airnode,\n endpointId,\n requester,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the expiration of the temporary whitelist of `requester`\n /// for the `airnode`–`endpointId` pair if the sender has the whitelist\n /// expiration setter role\n /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function setWhitelistExpiration(\n address airnode,\n bytes32 endpointId,\n address requester,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationSetterRoleOrIsManager(msg.sender),\n \"Cannot set expiration\"\n );\n _setWhitelistExpirationAndEmit(\n airnode,\n endpointId,\n requester,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the indefinite whitelist status of `requester` for the\n /// `airnode`–`endpointId` pair if the sender has the indefinite\n /// whitelister role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param status Indefinite whitelist status\n function setIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n bool status\n ) external override {\n require(\n hasIndefiniteWhitelisterRoleOrIsManager(msg.sender),\n \"Cannot set indefinite status\"\n );\n _setIndefiniteWhitelistStatusAndEmit(\n airnode,\n endpointId,\n requester,\n status\n );\n }\n\n /// @notice Revokes the indefinite whitelist status granted by a specific\n /// account that no longer has the indefinite whitelister role\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param requester Requester address\n /// @param setter Setter of the indefinite whitelist status\n function revokeIndefiniteWhitelistStatus(\n address airnode,\n bytes32 endpointId,\n address requester,\n address setter\n ) external override {\n require(\n !hasIndefiniteWhitelisterRoleOrIsManager(setter),\n \"setter can set indefinite status\"\n );\n _revokeIndefiniteWhitelistStatusAndEmit(\n airnode,\n endpointId,\n requester,\n setter\n );\n }\n}\n" + }, + "contracts/rrp/AirnodeRrpV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"./AuthorizationUtilsV0.sol\";\nimport \"./TemplateUtilsV0.sol\";\nimport \"./WithdrawalUtilsV0.sol\";\nimport \"./interfaces/IAirnodeRrpV0.sol\";\n\n/// @title Contract that implements the Airnode request–response protocol (RRP)\ncontract AirnodeRrpV0 is\n AuthorizationUtilsV0,\n TemplateUtilsV0,\n WithdrawalUtilsV0,\n IAirnodeRrpV0\n{\n using ECDSA for bytes32;\n\n /// @notice Called to get the sponsorship status for a sponsor–requester\n /// pair\n mapping(address => mapping(address => bool))\n public\n override sponsorToRequesterToSponsorshipStatus;\n\n /// @notice Called to get the request count of the requester plus one\n /// @dev Can be used to calculate the ID of the next request the requester\n /// will make\n mapping(address => uint256) public override requesterToRequestCountPlusOne;\n\n /// @dev Hash of expected fulfillment parameters are kept to verify that\n /// the fulfillment will be done with the correct parameters. This value is\n /// also used to check if the fulfillment for the particular request is\n /// expected, i.e., if there are recorded fulfillment parameters.\n mapping(bytes32 => bytes32) private requestIdToFulfillmentParameters;\n\n /// @notice Called by the sponsor to set the sponsorship status of a\n /// requester, i.e., allow or disallow a requester to make requests that\n /// will be fulfilled by the sponsor wallet\n /// @dev This is not Airnode-specific, i.e., the sponsor allows the\n /// requester's requests to be fulfilled through its sponsor wallets across\n /// all Airnodes\n /// @param requester Requester address\n /// @param sponsorshipStatus Sponsorship status\n function setSponsorshipStatus(address requester, bool sponsorshipStatus)\n external\n override\n {\n // Initialize the requester request count for consistent request gas\n // cost\n if (requesterToRequestCountPlusOne[requester] == 0) {\n requesterToRequestCountPlusOne[requester] = 1;\n }\n sponsorToRequesterToSponsorshipStatus[msg.sender][\n requester\n ] = sponsorshipStatus;\n emit SetSponsorshipStatus(msg.sender, requester, sponsorshipStatus);\n }\n\n /// @notice Called by the requester to make a request that refers to a\n /// template for the Airnode address, endpoint ID and parameters\n /// @dev `fulfillAddress` is not allowed to be the address of this\n /// contract. This is not actually needed to protect users that use the\n /// protocol as intended, but it is done for good measure.\n /// @param templateId Template ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill the\n /// request\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @param parameters Parameters provided by the requester in addition to\n /// the parameters in the template\n /// @return requestId Request ID\n function makeTemplateRequest(\n bytes32 templateId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external override returns (bytes32 requestId) {\n address airnode = templates[templateId].airnode;\n // If the Airnode address of the template is zero the template does not\n // exist because template creation does not allow zero Airnode address\n require(airnode != address(0), \"Template does not exist\");\n require(fulfillAddress != address(this), \"Fulfill address AirnodeRrp\");\n require(\n sponsorToRequesterToSponsorshipStatus[sponsor][msg.sender],\n \"Requester not sponsored\"\n );\n uint256 requesterRequestCount = requesterToRequestCountPlusOne[\n msg.sender\n ];\n requestId = keccak256(\n abi.encodePacked(\n block.chainid,\n address(this),\n msg.sender,\n requesterRequestCount,\n templateId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n )\n );\n requestIdToFulfillmentParameters[requestId] = keccak256(\n abi.encodePacked(\n airnode,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId\n )\n );\n requesterToRequestCountPlusOne[msg.sender]++;\n emit MadeTemplateRequest(\n airnode,\n requestId,\n requesterRequestCount,\n block.chainid,\n msg.sender,\n templateId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n );\n }\n\n /// @notice Called by the requester to make a full request, which provides\n /// all of its parameters as arguments and does not refer to a template\n /// @dev `fulfillAddress` is not allowed to be the address of this\n /// contract. This is not actually needed to protect users that use the\n /// protocol as intended, but it is done for good measure.\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill\n /// the request\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @param parameters All request parameters\n /// @return requestId Request ID\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external override returns (bytes32 requestId) {\n require(airnode != address(0), \"Airnode address zero\");\n require(fulfillAddress != address(this), \"Fulfill address AirnodeRrp\");\n require(\n sponsorToRequesterToSponsorshipStatus[sponsor][msg.sender],\n \"Requester not sponsored\"\n );\n uint256 requesterRequestCount = requesterToRequestCountPlusOne[\n msg.sender\n ];\n requestId = keccak256(\n abi.encodePacked(\n block.chainid,\n address(this),\n msg.sender,\n requesterRequestCount,\n airnode,\n endpointId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n )\n );\n requestIdToFulfillmentParameters[requestId] = keccak256(\n abi.encodePacked(\n airnode,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId\n )\n );\n requesterToRequestCountPlusOne[msg.sender]++;\n emit MadeFullRequest(\n airnode,\n requestId,\n requesterRequestCount,\n block.chainid,\n msg.sender,\n endpointId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n );\n }\n\n /// @notice Called by Airnode to fulfill the request (template or full)\n /// @dev The data is ABI-encoded as a `bytes` type, with its format\n /// depending on the request specifications.\n /// This will not revert depending on the external call. However, it will\n /// return `false` if the external call reverts or if there is no function\n /// with a matching signature at `fulfillAddress`. On the other hand, it\n /// will return `true` if the external call returns successfully or if\n /// there is no contract deployed at `fulfillAddress`.\n /// If `callSuccess` is `false`, `callData` can be decoded to retrieve the\n /// revert string.\n /// This function emits its event after an untrusted low-level call,\n /// meaning that the order of these events within the transaction should\n /// not be taken seriously, yet the content will be sound.\n /// @param requestId Request ID\n /// @param airnode Airnode address\n /// @param data Fulfillment data\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @return callSuccess If the fulfillment call succeeded\n /// @return callData Data returned by the fulfillment call (if there is\n /// any)\n function fulfill(\n bytes32 requestId,\n address airnode,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata data,\n bytes calldata signature\n ) external override returns (bool callSuccess, bytes memory callData) {\n require(\n keccak256(\n abi.encodePacked(\n airnode,\n msg.sender,\n fulfillAddress,\n fulfillFunctionId\n )\n ) == requestIdToFulfillmentParameters[requestId],\n \"Invalid request fulfillment\"\n );\n require(\n (\n keccak256(abi.encodePacked(requestId, data))\n .toEthSignedMessageHash()\n ).recover(signature) == airnode,\n \"Invalid signature\"\n );\n delete requestIdToFulfillmentParameters[requestId];\n (callSuccess, callData) = fulfillAddress.call( // solhint-disable-line avoid-low-level-calls\n abi.encodeWithSelector(fulfillFunctionId, requestId, data)\n );\n if (callSuccess) {\n emit FulfilledRequest(airnode, requestId, data);\n } else {\n // We do not bubble up the revert string from `callData`\n emit FailedRequest(\n airnode,\n requestId,\n \"Fulfillment failed unexpectedly\"\n );\n }\n }\n\n /// @notice Called by Airnode if the request cannot be fulfilled\n /// @dev Airnode should fall back to this if a request cannot be fulfilled\n /// because static call to `fulfill()` returns `false` for `callSuccess`\n /// @param requestId Request ID\n /// @param airnode Airnode address\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @param errorMessage A message that explains why the request has failed\n function fail(\n bytes32 requestId,\n address airnode,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n string calldata errorMessage\n ) external override {\n require(\n keccak256(\n abi.encodePacked(\n airnode,\n msg.sender,\n fulfillAddress,\n fulfillFunctionId\n )\n ) == requestIdToFulfillmentParameters[requestId],\n \"Invalid request fulfillment\"\n );\n delete requestIdToFulfillmentParameters[requestId];\n emit FailedRequest(airnode, requestId, errorMessage);\n }\n\n /// @notice Called to check if the request with the ID is made but not\n /// fulfilled/failed yet\n /// @dev If a requester has made a request, received a request ID but did\n /// not hear back, it can call this method to check if the Airnode has\n /// called back `fail()` instead.\n /// @param requestId Request ID\n /// @return isAwaitingFulfillment If the request is awaiting fulfillment\n /// (i.e., `true` if `fulfill()` or `fail()` is not called back yet,\n /// `false` otherwise)\n function requestIsAwaitingFulfillment(bytes32 requestId)\n external\n view\n override\n returns (bool isAwaitingFulfillment)\n {\n isAwaitingFulfillment =\n requestIdToFulfillmentParameters[requestId] != bytes32(0);\n }\n}\n" + }, + "contracts/rrp/AirnodeRrpV0DryRun.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\n\n/// @title Contract that complements Airnode request–response protocol (RRP) to\n/// allow Airnode to estimate the gas required to execute a fulfillment\n/// @dev Typically, contracts are built to revert when an external call they\n/// make reverts. In contrast, AirnodeRrpV0 does not revert when the external\n/// call during the fulfillment reverts, and instead fails gracefully by\n/// emitting a `FailedRequest` event. This event signals to the future\n/// invocations of the stateless Airnode to not retry the failed fulfillment.\n/// Although this approach meets the intended purpose, it disables Airnode from\n/// calling `eth_estimateGas` on `fulfill()` to estimate the gas amount that\n/// will be used to execute a fulfillment successfully. Specifically, since\n/// `eth_estimateGas` looks for the lowest gas limit that results in the\n/// transaction not reverting, and AirnodeRrpV0's `fulfill()` does not revert\n/// when its external call reverts (because it runs out of gas),\n/// `eth_estimateGas` will not necessarily return a gas amount that will result\n/// in the fulfillment to be successful even if such an amount exists.\n/// As a solution, Airnode calls `eth_estimateGas` on AirnodeRrpV0DryRun's\n/// `fulfill()` and the external call of the fulfillment, and add these up to\n/// find the gas limit required to execute a successful fulfillment. This\n/// sum is an overestimation of the actual requirement, as it includes an\n/// additional base fee (21,000 gas on Ethereum).\ncontract AirnodeRrpV0DryRun\n{\n using ECDSA for bytes32;\n\n event FulfilledRequest(\n address indexed airnode,\n bytes32 indexed requestId,\n bytes data\n );\n\n /// @dev This mapping is kept as it is in AirnodeRrpV0 to closely simulate\n /// the fulfillment. All of its keys will map to zero values.\n mapping(bytes32 => bytes32) private requestIdToFulfillmentParameters;\n\n /// @notice Used by Airnode to estimate the gas amount needed to fulfill\n /// the request (excluding the external call). Do not call this function,\n /// as it will have no practical effect.\n /// @dev Refer to AirnodeRrpV0's `fulfill()` for more information\n /// @param requestId Request ID\n /// @param airnode Airnode address\n /// @param data Fulfillment data\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @return callSuccess If the fulfillment call succeeded\n /// @return callData Data returned by the fulfillment call (if there is\n /// any)\n function fulfill(\n bytes32 requestId,\n address airnode,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata data,\n bytes calldata signature\n ) external returns (bool callSuccess, bytes memory callData) {\n // The line below is kept the same, except that the condition is\n // reversed to ensure that it never reverts. All\n // `requestIdToFulfillmentParameters` values are zero and virtually no\n // `keccak256()` output will be equal to that.\n require(\n keccak256(\n abi.encodePacked(\n airnode,\n msg.sender,\n fulfillAddress,\n fulfillFunctionId\n )\n ) != requestIdToFulfillmentParameters[requestId],\n \"Dummy revert string\"\n );\n // The line below does not need to be modified\n require(\n (\n keccak256(abi.encodePacked(requestId, data))\n .toEthSignedMessageHash()\n ).recover(signature) == airnode,\n \"Invalid signature\"\n );\n // We cannot call `fulfillAddress` below because (1) we do not want\n // this function to actually fulfill the request (2) the fulfill\n // function will be behind an `onlyAirnodeRrp` modifier and will reject\n // the calls from AirnodeRrpV0DryRun.\n // Instead, we call an address that we know to not contain any\n // bytecode, which will result in the call to not revert or spend extra\n // gas. Since we have already confirmed that `airnode` has signed a\n // hash, it is guaranteed to be an EOA and we can use it as a dummy\n // call target.\n (callSuccess, callData) = airnode.call( // solhint-disable-line avoid-low-level-calls\n abi.encodeWithSelector(fulfillFunctionId, requestId, data)\n );\n // If the external call above does not succeed, the `eth_estimateGas`\n // called on the external call will not be able to return a gas amount.\n // AirnodeRrpV0DryRun's `fulfill()` optimistically estimates the\n // AirnodeRrpV0 overhead of a fulfillment, and expects Airnode to\n // detect if the external call will succeed (by calling\n // `eth_estimateGas` on it) independently. Therefore, we do not need to\n // consider the unhappy path here.\n if (callSuccess) {\n emit FulfilledRequest(airnode, requestId, data);\n }\n }\n}\n" + }, + "contracts/rrp/AuthorizationUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interfaces/IAuthorizationUtilsV0.sol\";\nimport \"../authorizers/interfaces/IAuthorizerV0.sol\";\n\n/// @title Contract that implements authorization checks\ncontract AuthorizationUtilsV0 is IAuthorizationUtilsV0 {\n /// @notice Uses the authorizer contracts of an Airnode to decide if a\n /// request is authorized. Once an Airnode receives a request, it calls\n /// this method to determine if it should respond. Similarly, third parties\n /// can use this method to determine if a particular request would be\n /// authorized.\n /// @dev This method is meant to be called off-chain, statically by the\n /// Airnode to decide if it should respond to a request. The requester can\n /// also call it, yet this function returning true should not be taken as a\n /// guarantee of the subsequent request being fulfilled.\n /// It is enough for only one of the authorizer contracts to return true\n /// for the request to be authorized.\n /// @param authorizers Authorizer contract addresses\n /// @param airnode Airnode address\n /// @param requestId Request ID\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param requester Requester address\n /// @return status Authorization status of the request\n function checkAuthorizationStatus(\n address[] calldata authorizers,\n address airnode,\n bytes32 requestId,\n bytes32 endpointId,\n address sponsor,\n address requester\n ) public view override returns (bool status) {\n for (uint256 ind = 0; ind < authorizers.length; ind++) {\n IAuthorizerV0 authorizer = IAuthorizerV0(authorizers[ind]);\n if (\n authorizer.isAuthorizedV0(\n requestId,\n airnode,\n endpointId,\n sponsor,\n requester\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n /// @notice A convenience function to make multiple authorization status\n /// checks with a single call\n /// @param authorizers Authorizer contract addresses\n /// @param airnode Airnode address\n /// @param requestIds Request IDs\n /// @param endpointIds Endpoint IDs\n /// @param sponsors Sponsor addresses\n /// @param requesters Requester addresses\n /// @return statuses Authorization statuses of the request\n function checkAuthorizationStatuses(\n address[] calldata authorizers,\n address airnode,\n bytes32[] calldata requestIds,\n bytes32[] calldata endpointIds,\n address[] calldata sponsors,\n address[] calldata requesters\n ) external view override returns (bool[] memory statuses) {\n require(\n requestIds.length == endpointIds.length &&\n requestIds.length == sponsors.length &&\n requestIds.length == requesters.length,\n \"Unequal parameter lengths\"\n );\n statuses = new bool[](requestIds.length);\n for (uint256 ind = 0; ind < requestIds.length; ind++) {\n statuses[ind] = checkAuthorizationStatus(\n authorizers,\n airnode,\n requestIds[ind],\n endpointIds[ind],\n sponsors[ind],\n requesters[ind]\n );\n }\n }\n}\n" + }, + "contracts/rrp/interfaces/IAirnodeRrpV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IAuthorizationUtilsV0.sol\";\nimport \"./ITemplateUtilsV0.sol\";\nimport \"./IWithdrawalUtilsV0.sol\";\n\ninterface IAirnodeRrpV0 is\n IAuthorizationUtilsV0,\n ITemplateUtilsV0,\n IWithdrawalUtilsV0\n{\n event SetSponsorshipStatus(\n address indexed sponsor,\n address indexed requester,\n bool sponsorshipStatus\n );\n\n event MadeTemplateRequest(\n address indexed airnode,\n bytes32 indexed requestId,\n uint256 requesterRequestCount,\n uint256 chainId,\n address requester,\n bytes32 templateId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes parameters\n );\n\n event MadeFullRequest(\n address indexed airnode,\n bytes32 indexed requestId,\n uint256 requesterRequestCount,\n uint256 chainId,\n address requester,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes parameters\n );\n\n event FulfilledRequest(\n address indexed airnode,\n bytes32 indexed requestId,\n bytes data\n );\n\n event FailedRequest(\n address indexed airnode,\n bytes32 indexed requestId,\n string errorMessage\n );\n\n function setSponsorshipStatus(address requester, bool sponsorshipStatus)\n external;\n\n function makeTemplateRequest(\n bytes32 templateId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external returns (bytes32 requestId);\n\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external returns (bytes32 requestId);\n\n function fulfill(\n bytes32 requestId,\n address airnode,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata data,\n bytes calldata signature\n ) external returns (bool callSuccess, bytes memory callData);\n\n function fail(\n bytes32 requestId,\n address airnode,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n string calldata errorMessage\n ) external;\n\n function sponsorToRequesterToSponsorshipStatus(\n address sponsor,\n address requester\n ) external view returns (bool sponsorshipStatus);\n\n function requesterToRequestCountPlusOne(address requester)\n external\n view\n returns (uint256 requestCountPlusOne);\n\n function requestIsAwaitingFulfillment(bytes32 requestId)\n external\n view\n returns (bool isAwaitingFulfillment);\n}\n" + }, + "contracts/rrp/interfaces/IAuthorizationUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IAuthorizationUtilsV0 {\n function checkAuthorizationStatus(\n address[] calldata authorizers,\n address airnode,\n bytes32 requestId,\n bytes32 endpointId,\n address sponsor,\n address requester\n ) external view returns (bool status);\n\n function checkAuthorizationStatuses(\n address[] calldata authorizers,\n address airnode,\n bytes32[] calldata requestIds,\n bytes32[] calldata endpointIds,\n address[] calldata sponsors,\n address[] calldata requesters\n ) external view returns (bool[] memory statuses);\n}\n" + }, + "contracts/rrp/interfaces/ITemplateUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ITemplateUtilsV0 {\n event CreatedTemplate(\n bytes32 indexed templateId,\n address airnode,\n bytes32 endpointId,\n bytes parameters\n );\n\n function createTemplate(\n address airnode,\n bytes32 endpointId,\n bytes calldata parameters\n ) external returns (bytes32 templateId);\n\n function getTemplates(bytes32[] calldata templateIds)\n external\n view\n returns (\n address[] memory airnodes,\n bytes32[] memory endpointIds,\n bytes[] memory parameters\n );\n\n function templates(bytes32 templateId)\n external\n view\n returns (\n address airnode,\n bytes32 endpointId,\n bytes memory parameters\n );\n}\n" + }, + "contracts/rrp/interfaces/IWithdrawalUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWithdrawalUtilsV0 {\n event RequestedWithdrawal(\n address indexed airnode,\n address indexed sponsor,\n bytes32 indexed withdrawalRequestId,\n address sponsorWallet\n );\n\n event FulfilledWithdrawal(\n address indexed airnode,\n address indexed sponsor,\n bytes32 indexed withdrawalRequestId,\n address sponsorWallet,\n uint256 amount\n );\n\n function requestWithdrawal(address airnode, address sponsorWallet) external;\n\n function fulfillWithdrawal(\n bytes32 withdrawalRequestId,\n address airnode,\n address sponsor\n ) external payable;\n\n function sponsorToWithdrawalRequestCount(address sponsor)\n external\n view\n returns (uint256 withdrawalRequestCount);\n}\n" + }, + "contracts/rrp/requesters/interfaces/IRrpBeaconServerV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../../whitelist/interfaces/IWhitelistWithManager.sol\";\n\ninterface IRrpBeaconServerV0 is IWhitelistWithManager {\n event SetUpdatePermissionStatus(\n address indexed sponsor,\n address indexed updateRequester,\n bool status\n );\n\n event RequestedBeaconUpdate(\n bytes32 indexed beaconId,\n address indexed sponsor,\n address indexed requester,\n bytes32 requestId,\n bytes32 templateId,\n address sponsorWallet,\n bytes parameters\n );\n\n event UpdatedBeacon(\n bytes32 indexed beaconId,\n bytes32 requestId,\n int224 value,\n uint32 timestamp\n );\n\n function setUpdatePermissionStatus(address updateRequester, bool status)\n external;\n\n function requestBeaconUpdate(\n bytes32 beaconId,\n address requester,\n address designatedWallet,\n bytes calldata parameters\n ) external;\n\n function fulfill(bytes32 requestId, bytes calldata data) external;\n\n function readBeacon(bytes32 beaconId)\n external\n view\n returns (int224 value, uint32 timestamp);\n\n function readerCanReadBeacon(bytes32 beaconId, address reader)\n external\n view\n returns (bool);\n\n function beaconIdToReaderToWhitelistStatus(bytes32 beaconId, address reader)\n external\n view\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount);\n\n function beaconIdToReaderToSetterToIndefiniteWhitelistStatus(\n bytes32 beaconId,\n address reader,\n address setter\n ) external view returns (bool indefiniteWhitelistStatus);\n\n function sponsorToUpdateRequesterToPermissionStatus(\n address sponsor,\n address updateRequester\n ) external view returns (bool permissionStatus);\n\n function deriveBeaconId(bytes32 templateId, bytes calldata parameters)\n external\n pure\n returns (bytes32 beaconId);\n}\n" + }, + "contracts/rrp/requesters/mock/MockRrpRequesterV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../RrpRequesterV0.sol\";\n\n/// @title A mock Airnode RRP requester contract\ncontract MockRrpRequesterV0 is RrpRequesterV0 {\n event FulfilledRequest(bytes32 indexed requestId, bytes data);\n\n mapping(bytes32 => bytes) public requestIdToData;\n\n mapping(bytes32 => bool) private expectingRequestWithIdToBeFulfilled;\n\n /// @param airnodeRrpAddress Airnode RRP contract address\n constructor(address airnodeRrpAddress) RrpRequesterV0(airnodeRrpAddress) {}\n\n /// @notice A wrapper for the respective method at AirnodeRrp.sol for\n /// testing\n /// @param templateId Template ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill\n /// the request\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @param parameters Parameters provided by the requester in addition to\n /// the parameters in the template\n function makeTemplateRequest(\n bytes32 templateId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external {\n bytes32 requestId = airnodeRrp.makeTemplateRequest(\n templateId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n );\n expectingRequestWithIdToBeFulfilled[requestId] = true;\n }\n\n /// @notice A wrapper for the respective method at AirnodeRrp.sol for\n /// testing\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet that is requested to fulfill\n /// the request\n /// @param fulfillAddress Address that will be called to fulfill\n /// @param fulfillFunctionId Signature of the function that will be called\n /// to fulfill\n /// @param parameters All request parameters\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external {\n bytes32 requestId = airnodeRrp.makeFullRequest(\n airnode,\n endpointId,\n sponsor,\n sponsorWallet,\n fulfillAddress,\n fulfillFunctionId,\n parameters\n );\n expectingRequestWithIdToBeFulfilled[requestId] = true;\n }\n\n /// @notice A method to be called back by the respective method at\n /// AirnodeRrp.sol for testing\n /// @param requestId Request ID\n /// @param data Data returned by the Airnode\n function fulfill(bytes32 requestId, bytes calldata data)\n external\n onlyAirnodeRrp\n {\n require(\n expectingRequestWithIdToBeFulfilled[requestId],\n \"No such request made\"\n );\n delete expectingRequestWithIdToBeFulfilled[requestId];\n requestIdToData[requestId] = data;\n emit FulfilledRequest(requestId, data);\n }\n\n /// @notice A method to be called back by the respective method at\n /// AirnodeRrp.sol for testing fulfillment failure\n /// @param requestId Request ID\n /// @param data Data returned by the Airnode\n function fulfillAlwaysReverts(\n bytes32 requestId, // solhint-disable-line no-unused-vars\n bytes calldata data // solhint-disable-line no-unused-vars\n ) external view onlyAirnodeRrp {\n revert(\"Always reverts\");\n }\n\n /// @notice A method to be called back by the respective method at\n /// AirnodeRrp.sol for testing fulfillment failure\n /// @param requestId Request ID\n /// @param data Data returned by the Airnode\n function fulfillAlwaysRevertsWithNoString(\n bytes32 requestId, // solhint-disable-line no-unused-vars\n bytes calldata data // solhint-disable-line no-unused-vars\n ) external view onlyAirnodeRrp {\n revert(); // solhint-disable-line reason-string\n }\n\n /// @notice A method to be called back by the respective method at\n /// AirnodeRrp.sol for testing fulfillment running out of gas\n /// @param requestId Request ID\n /// @param data Data returned by the Airnode\n function fulfillAlwaysRunsOutOfGas(\n bytes32 requestId, // solhint-disable-line no-unused-vars\n bytes calldata data // solhint-disable-line no-unused-vars\n ) external view onlyAirnodeRrp {\n while (true) {}\n }\n\n /// @notice A wrapper for the respective method at AirnodeRrp.sol for\n /// testing\n /// @dev The withdrawal requested by calling this will revert because this\n /// contract does not implement a default payable method\n /// @param airnode Airnode address\n /// @param sponsorWallet Sponsor wallet that the withdrawal is requested\n /// from\n function requestWithdrawal(address airnode, address sponsorWallet)\n external\n {\n airnodeRrp.requestWithdrawal(airnode, sponsorWallet);\n }\n}\n" + }, + "contracts/rrp/requesters/RrpBeaconServerV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"../../whitelist/WhitelistWithManager.sol\";\nimport \"./RrpRequesterV0.sol\";\nimport \"./interfaces/IRrpBeaconServerV0.sol\";\n\n/// @title The contract that serves beacons using Airnode RRP\n/// @notice A beacon is a live data point associated with a beacon ID, which is\n/// derived from a template ID and additional parameters. This is suitable\n/// where the more recent data point is always more favorable, e.g., in the\n/// context of an asset price data feed. Another definition of beacons are\n/// one-Airnode data feeds that can be used individually or combined to build\n/// decentralized data feeds.\n/// @dev This contract casts the reported data point to `int224`. If this is\n/// a problem (because the reported data may not fit into 224 bits or it is of\n/// a completely different type such as `bytes32`), do not use this contract\n/// and implement a customized version instead.\n/// The contract casts the timestamps to `uint32`, which means it will not work\n/// work past-2106 in the current form. If this is an issue, consider casting\n/// the timestamps to a larger type.\ncontract RrpBeaconServerV0 is\n WhitelistWithManager,\n RrpRequesterV0,\n IRrpBeaconServerV0\n{\n struct Beacon {\n int224 value;\n uint32 timestamp;\n }\n\n /// @notice Returns if a sponsor has permitted an account to request\n /// updates at this contract\n mapping(address => mapping(address => bool))\n public\n override sponsorToUpdateRequesterToPermissionStatus;\n\n mapping(bytes32 => Beacon) private beacons;\n mapping(bytes32 => bytes32) private requestIdToBeaconId;\n\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n /// @param _manager Manager address\n /// @param _airnodeRrp Airnode RRP contract address\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription,\n address _manager,\n address _airnodeRrp\n )\n WhitelistWithManager(\n _accessControlRegistry,\n _adminRoleDescription,\n _manager\n )\n RrpRequesterV0(_airnodeRrp)\n {}\n\n /// @notice Called by the sponsor to set the update request permission\n /// status of an account\n /// @param updateRequester Update requester address\n /// @param status Update permission status of the update requester\n function setUpdatePermissionStatus(address updateRequester, bool status)\n external\n override\n {\n require(updateRequester != address(0), \"Update requester zero\");\n sponsorToUpdateRequesterToPermissionStatus[msg.sender][\n updateRequester\n ] = status;\n emit SetUpdatePermissionStatus(msg.sender, updateRequester, status);\n }\n\n /// @notice Called to request a beacon to be updated\n /// @dev There are two requirements for this method to be called: (1) The\n /// sponsor must call `setSponsorshipStatus()` of AirnodeRrp to sponsor\n /// this RrpBeaconServer contract, (2) The sponsor must call\n /// `setUpdatePermissionStatus()` of this RrpBeaconServer contract to give\n /// request update permission to the caller of this method.\n /// The template and additional parameters used here must specify a single\n /// point of data of type `int256` and an additional timestamp of type\n /// `uint256` to be returned because this is what `fulfill()` expects.\n /// This point of data must be castable to `int224` and the timestamp must\n /// be castable to `uint32`.\n /// @param templateId Template ID of the beacon to be updated\n /// @param sponsor Sponsor whose wallet will be used to fulfill this\n /// request\n /// @param sponsorWallet Sponsor wallet that will be used to fulfill this\n /// request\n /// @param parameters Parameters provided by the requester in addition to\n /// the parameters in the template\n function requestBeaconUpdate(\n bytes32 templateId,\n address sponsor,\n address sponsorWallet,\n bytes calldata parameters\n ) external override {\n require(\n sponsorToUpdateRequesterToPermissionStatus[sponsor][msg.sender],\n \"Caller not permitted\"\n );\n bytes32 beaconId = deriveBeaconId(templateId, parameters);\n bytes32 requestId = airnodeRrp.makeTemplateRequest(\n templateId,\n sponsor,\n sponsorWallet,\n address(this),\n this.fulfill.selector,\n parameters\n );\n requestIdToBeaconId[requestId] = beaconId;\n emit RequestedBeaconUpdate(\n beaconId,\n sponsor,\n msg.sender,\n requestId,\n templateId,\n sponsorWallet,\n parameters\n );\n }\n\n /// @notice Called by AirnodeRrp to fulfill the request\n /// @dev It is assumed that the fulfillment will be made with a single\n /// point of data of type `int256` and an additional timestamp of type\n /// `uint256`\n /// @param requestId ID of the request being fulfilled\n /// @param data Fulfillment data (a single `int256` and an additional\n /// timestamp of type `uint256` encoded as `bytes`)\n function fulfill(bytes32 requestId, bytes calldata data)\n external\n override\n onlyAirnodeRrp\n {\n bytes32 beaconId = requestIdToBeaconId[requestId];\n require(beaconId != bytes32(0), \"No such request made\");\n delete requestIdToBeaconId[requestId];\n (int256 decodedData, uint256 decodedTimestamp) = abi.decode(\n data,\n (int256, uint256)\n );\n require(\n decodedData >= type(int224).min && decodedData <= type(int224).max,\n \"Value typecasting error\"\n );\n require(\n decodedTimestamp <= type(uint32).max,\n \"Timestamp typecasting error\"\n );\n require(\n decodedTimestamp > beacons[beaconId].timestamp,\n \"Fulfillment older than beacon\"\n );\n require(\n decodedTimestamp + 1 hours > block.timestamp,\n \"Fulfillment stale\"\n );\n require(\n decodedTimestamp - 1 hours < block.timestamp,\n \"Fulfillment from future\"\n );\n beacons[beaconId] = Beacon({\n value: int224(decodedData),\n timestamp: uint32(decodedTimestamp)\n });\n emit UpdatedBeacon(\n beaconId,\n requestId,\n int224(decodedData),\n uint32(decodedTimestamp)\n );\n }\n\n /// @notice Called to read the beacon\n /// @dev The caller must be whitelisted.\n /// If the `timestamp` of a beacon is zero, this means that it was never\n /// written to before, and the zero value in the `value` field is not\n /// valid. In general, make sure to check if the timestamp of the beacon is\n /// fresh enough, and definitely disregard beacons with zero `timestamp`.\n /// @param beaconId ID of the beacon that will be returned\n /// @return value Beacon value\n /// @return timestamp Beacon timestamp\n function readBeacon(bytes32 beaconId)\n external\n view\n override\n returns (int224 value, uint32 timestamp)\n {\n require(\n readerCanReadBeacon(beaconId, msg.sender),\n \"Caller not whitelisted\"\n );\n Beacon storage beacon = beacons[beaconId];\n return (beacon.value, beacon.timestamp);\n }\n\n /// @notice Called to check if a reader is whitelisted to read the beacon\n /// @param beaconId Beacon ID\n /// @param reader Reader address\n /// @return isWhitelisted If the reader is whitelisted\n function readerCanReadBeacon(bytes32 beaconId, address reader)\n public\n view\n override\n returns (bool)\n {\n return userIsWhitelisted(beaconId, reader) || reader == address(0);\n }\n\n /// @notice Called to get the detailed whitelist status of the reader for\n /// the beacon\n /// @param beaconId Beacon ID\n /// @param reader Reader address\n /// @return expirationTimestamp Timestamp at which the whitelisting of the\n /// reader will expire\n /// @return indefiniteWhitelistCount Number of times `reader` was\n /// whitelisted indefinitely for `templateId`\n function beaconIdToReaderToWhitelistStatus(bytes32 beaconId, address reader)\n external\n view\n override\n returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount)\n {\n WhitelistStatus\n storage whitelistStatus = serviceIdToUserToWhitelistStatus[\n beaconId\n ][reader];\n expirationTimestamp = whitelistStatus.expirationTimestamp;\n indefiniteWhitelistCount = whitelistStatus.indefiniteWhitelistCount;\n }\n\n /// @notice Returns if an account has indefinitely whitelisted the reader\n /// for the beacon\n /// @param beaconId Beacon ID\n /// @param reader Reader address\n /// @param setter Address of the account that has potentially whitelisted\n /// the reader for the beacon indefinitely\n /// @return indefiniteWhitelistStatus If `setter` has indefinitely\n /// whitelisted reader for the beacon\n function beaconIdToReaderToSetterToIndefiniteWhitelistStatus(\n bytes32 beaconId,\n address reader,\n address setter\n ) external view override returns (bool indefiniteWhitelistStatus) {\n indefiniteWhitelistStatus = serviceIdToUserToSetterToIndefiniteWhitelistStatus[\n beaconId\n ][reader][setter];\n }\n\n /// @notice Derives the beacon ID from the respective template ID and\n /// additional parameters\n /// @param templateId Template ID\n /// @param parameters Parameters provided by the requester in addition to\n /// the parameters in the template\n /// @return beaconId Beacon ID\n function deriveBeaconId(bytes32 templateId, bytes calldata parameters)\n public\n pure\n override\n returns (bytes32 beaconId)\n {\n beaconId = keccak256(abi.encodePacked(templateId, parameters));\n }\n}\n" + }, + "contracts/rrp/requesters/RrpRequesterV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/IAirnodeRrpV0.sol\";\n\n/// @title The contract to be inherited to make Airnode RRP requests\ncontract RrpRequesterV0 {\n IAirnodeRrpV0 public immutable airnodeRrp;\n\n /// @dev Reverts if the caller is not the Airnode RRP contract.\n /// Use it as a modifier for fulfill and error callback methods, but also\n /// check `requestId`.\n modifier onlyAirnodeRrp() {\n require(msg.sender == address(airnodeRrp), \"Caller not Airnode RRP\");\n _;\n }\n\n /// @dev Airnode RRP address is set at deployment and is immutable.\n /// RrpRequester is made its own sponsor by default. RrpRequester can also\n /// be sponsored by others and use these sponsorships while making\n /// requests, i.e., using this default sponsorship is optional.\n /// @param _airnodeRrp Airnode RRP contract address\n constructor(address _airnodeRrp) {\n airnodeRrp = IAirnodeRrpV0(_airnodeRrp);\n IAirnodeRrpV0(_airnodeRrp).setSponsorshipStatus(address(this), true);\n }\n}\n" + }, + "contracts/rrp/TemplateUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interfaces/ITemplateUtilsV0.sol\";\n\n/// @title Contract that implements request templates\ncontract TemplateUtilsV0 is ITemplateUtilsV0 {\n struct Template {\n address airnode;\n bytes32 endpointId;\n bytes parameters;\n }\n\n /// @notice Called to get a template\n mapping(bytes32 => Template) public override templates;\n\n /// @notice Creates a request template with the given parameters,\n /// addressable by the ID it returns\n /// @dev A specific set of request parameters will always have the same\n /// template ID. This means a few things: (1) You can compute the expected\n /// ID of a template before creating it, (2) Creating a new template with\n /// the same parameters will overwrite the old one and return the same ID,\n /// (3) After you query a template with its ID, you can verify its\n /// integrity by applying the hash and comparing the result with the ID.\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID (allowed to be `bytes32(0)`)\n /// @param parameters Static request parameters (i.e., parameters that will\n /// not change between requests, unlike the dynamic parameters determined\n /// at request-time)\n /// @return templateId Request template ID\n function createTemplate(\n address airnode,\n bytes32 endpointId,\n bytes calldata parameters\n ) external override returns (bytes32 templateId) {\n require(airnode != address(0), \"Airnode address zero\");\n templateId = keccak256(\n abi.encodePacked(airnode, endpointId, parameters)\n );\n templates[templateId] = Template({\n airnode: airnode,\n endpointId: endpointId,\n parameters: parameters\n });\n emit CreatedTemplate(templateId, airnode, endpointId, parameters);\n }\n\n /// @notice A convenience method to retrieve multiple templates with a\n /// single call\n /// @dev Does not revert if the templates being indexed do not exist\n /// @param templateIds Request template IDs\n /// @return airnodes Array of Airnode addresses\n /// @return endpointIds Array of endpoint IDs\n /// @return parameters Array of request parameters\n function getTemplates(bytes32[] calldata templateIds)\n external\n view\n override\n returns (\n address[] memory airnodes,\n bytes32[] memory endpointIds,\n bytes[] memory parameters\n )\n {\n airnodes = new address[](templateIds.length);\n endpointIds = new bytes32[](templateIds.length);\n parameters = new bytes[](templateIds.length);\n for (uint256 ind = 0; ind < templateIds.length; ind++) {\n Template storage template = templates[templateIds[ind]];\n airnodes[ind] = template.airnode;\n endpointIds[ind] = template.endpointId;\n parameters[ind] = template.parameters;\n }\n }\n}\n" + }, + "contracts/rrp/WithdrawalUtilsV0.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interfaces/IWithdrawalUtilsV0.sol\";\n\n/// @title Contract that implements logic for withdrawals from sponsor wallets\ncontract WithdrawalUtilsV0 is IWithdrawalUtilsV0 {\n /// @notice Called to get the withdrawal request count of the sponsor\n /// @dev Can be used to calculate the ID of the next withdrawal request the\n /// sponsor will make\n mapping(address => uint256) public override sponsorToWithdrawalRequestCount;\n\n /// @dev Hash of expected fulfillment parameters are kept to verify that\n /// the fulfillment will be done with the correct parameters\n mapping(bytes32 => bytes32) private withdrawalRequestIdToParameters;\n\n /// @notice Called by a sponsor to create a request for the Airnode to send\n /// the funds kept in the respective sponsor wallet to the sponsor\n /// @dev We do not need to use the withdrawal request parameters in the\n /// request ID hash to validate them at the node-side because all of the\n /// parameters are used during fulfillment and will get validated on-chain.\n /// The first withdrawal request a sponsor will make will cost slightly\n /// higher gas than the rest due to how the request counter is implemented.\n /// @param airnode Airnode address\n /// @param sponsorWallet Sponsor wallet that the withdrawal is requested\n /// from\n function requestWithdrawal(address airnode, address sponsorWallet)\n external\n override\n {\n bytes32 withdrawalRequestId = keccak256(\n abi.encodePacked(\n block.chainid,\n address(this),\n msg.sender,\n ++sponsorToWithdrawalRequestCount[msg.sender]\n )\n );\n withdrawalRequestIdToParameters[withdrawalRequestId] = keccak256(\n abi.encodePacked(airnode, msg.sender, sponsorWallet)\n );\n emit RequestedWithdrawal(\n airnode,\n msg.sender,\n withdrawalRequestId,\n sponsorWallet\n );\n }\n\n /// @notice Called by the Airnode using the sponsor wallet to fulfill the\n /// withdrawal request made by the sponsor\n /// @dev The Airnode sends the funds to the sponsor through this method\n /// to emit an event that indicates that the withdrawal request has been\n /// fulfilled\n /// @param withdrawalRequestId Withdrawal request ID\n /// @param airnode Airnode address\n /// @param sponsor Sponsor address\n function fulfillWithdrawal(\n bytes32 withdrawalRequestId,\n address airnode,\n address sponsor\n ) external payable override {\n require(\n withdrawalRequestIdToParameters[withdrawalRequestId] ==\n keccak256(abi.encodePacked(airnode, sponsor, msg.sender)),\n \"Invalid withdrawal fulfillment\"\n );\n delete withdrawalRequestIdToParameters[withdrawalRequestId];\n emit FulfilledWithdrawal(\n airnode,\n sponsor,\n withdrawalRequestId,\n msg.sender,\n msg.value\n );\n (bool success, ) = sponsor.call{value: msg.value}(\"\"); // solhint-disable-line avoid-low-level-calls\n require(success, \"Transfer failed\");\n }\n}\n" + }, + "contracts/utils/interfaces/IOwnableCallForwarder.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IOwnableCallForwarder {\n function forwardCall(\n address forwardTarget,\n bytes calldata forwardedCalldata\n ) external payable returns (bytes memory returnedData);\n}\n" + }, + "contracts/utils/mock/MockCallForwarderTarget.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\ncontract MockCallForwarderTarget {\n string public storage1;\n uint256 public storage2;\n\n function payableTargetFunction(\n string calldata input1,\n uint256 input2,\n uint256 msgValue\n ) external payable returns (bytes memory output1, bool output2) {\n require(\n keccak256(abi.encodePacked(input1)) ==\n keccak256(abi.encodePacked(\"input1\")),\n \"Incorrect input\"\n );\n require(input2 == 123, \"Incorrect input\");\n require(msg.value == msgValue, \"Incorrect value\");\n storage1 = input1;\n storage2 = input2;\n output1 = hex\"12345678\";\n output2 = true;\n }\n\n function nonpayableTargetFunction(string calldata input1, uint256 input2)\n external\n returns (bytes memory output1, bool output2)\n {\n require(\n keccak256(abi.encodePacked(input1)) ==\n keccak256(abi.encodePacked(\"input1\")),\n \"Incorrect input\"\n );\n require(input2 == 123, \"Incorrect input\");\n storage1 = input1;\n storage2 = input2;\n output1 = hex\"12345678\";\n output2 = true;\n }\n}\n" + }, + "contracts/utils/OwnableCallForwarder.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.9;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/IOwnableCallForwarder.sol\";\n\n/// @title Contract that forwards the calls that its owner sends\n/// @dev AccessControlRegistry users that want their access control tables\n/// to be transferrable (e.g., a DAO) will use this forwarder instead of\n/// interacting with it directly. There are cases where this transferrability\n/// is not desired, e.g., if the user is an Airnode and is immutably associated\n/// with a single address, in which case the manager will interact with\n/// AccessControlRegistry directly.\n/// The ownership of this contract is deliberately renouncable. If this does\n/// suit the use case, override and disable this functionality.\ncontract OwnableCallForwarder is Ownable, IOwnableCallForwarder {\n /// @notice Forwards the calldata and the value to the target address if\n /// the sender is the owner and returns the data\n /// @param forwardTarget Target address that the calldata will be forwarded\n /// to\n /// @param forwardedCalldata Calldata to be forwarded to the target address\n /// @return returnedData Data returned by the forwarded call\n function forwardCall(\n address forwardTarget,\n bytes calldata forwardedCalldata\n ) external payable override onlyOwner returns (bytes memory returnedData) {\n returnedData = Address.functionCallWithValue(\n forwardTarget,\n forwardedCalldata,\n msg.value\n );\n }\n}\n" + }, + "contracts/whitelist/interfaces/IWhitelistRoles.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWhitelistRoles {\n // solhint-disable-next-line func-name-mixedcase\n function WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION()\n external\n view\n returns (string memory);\n\n // solhint-disable-next-line func-name-mixedcase\n function WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION()\n external\n view\n returns (string memory);\n\n // solhint-disable-next-line func-name-mixedcase\n function INDEFINITE_WHITELISTER_ROLE_DESCRIPTION()\n external\n view\n returns (string memory);\n}\n" + }, + "contracts/whitelist/interfaces/IWhitelistRolesWithAirnode.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IWhitelistRoles.sol\";\nimport \"../../access-control-registry/interfaces/IAccessControlRegistryAdminned.sol\";\n\ninterface IWhitelistRolesWithAirnode is\n IWhitelistRoles,\n IAccessControlRegistryAdminned\n{\n function deriveAdminRole(address airnode)\n external\n view\n returns (bytes32 role);\n\n function deriveWhitelistExpirationExtenderRole(address airnode)\n external\n view\n returns (bytes32 role);\n\n function deriveWhitelistExpirationSetterRole(address airnode)\n external\n view\n returns (bytes32 role);\n\n function deriveIndefiniteWhitelisterRole(address airnode)\n external\n view\n returns (bytes32 role);\n}\n" + }, + "contracts/whitelist/interfaces/IWhitelistRolesWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IWhitelistRoles.sol\";\nimport \"../../access-control-registry/interfaces/IAccessControlRegistryAdminnedWithManager.sol\";\n\ninterface IWhitelistRolesWithManager is\n IWhitelistRoles,\n IAccessControlRegistryAdminnedWithManager\n{\n function whitelistExpirationExtenderRole() external view returns (bytes32);\n\n function whitelistExpirationSetterRole() external view returns (bytes32);\n\n function indefiniteWhitelisterRole() external view returns (bytes32);\n}\n" + }, + "contracts/whitelist/interfaces/IWhitelistWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IWhitelistRolesWithManager.sol\";\n\ninterface IWhitelistWithManager is IWhitelistRolesWithManager {\n event ExtendedWhitelistExpiration(\n bytes32 indexed serviceId,\n address indexed user,\n address indexed sender,\n uint256 expiration\n );\n\n event SetWhitelistExpiration(\n bytes32 indexed serviceId,\n address indexed user,\n address indexed sender,\n uint256 expiration\n );\n\n event SetIndefiniteWhitelistStatus(\n bytes32 indexed serviceId,\n address indexed user,\n address indexed sender,\n bool status,\n uint192 indefiniteWhitelistCount\n );\n\n event RevokedIndefiniteWhitelistStatus(\n bytes32 indexed serviceId,\n address indexed user,\n address indexed setter,\n address sender,\n uint192 indefiniteWhitelistCount\n );\n\n function extendWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) external;\n\n function setWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) external;\n\n function setIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n bool status\n ) external;\n\n function revokeIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n address setter\n ) external;\n}\n" + }, + "contracts/whitelist/Whitelist.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Contract to be inherited by contracts that need temporary and\n/// permanent whitelists for services identified by hashes\n/// @notice This contract implements two kinds of whitelisting:\n/// (1) Temporary, ends when the expiration timestamp is in the past\n/// (2) Indefinite, ends when the indefinite whitelist count is zero\n/// Multiple senders can indefinitely whitelist/unwhitelist independently. The\n/// user will be considered whitelisted as long as there is at least one active\n/// indefinite whitelisting.\n/// @dev The interface of this contract is not implemented. It should be\n/// inherited and its functions should be exposed with a sort of an\n/// authorization scheme.\ncontract Whitelist {\n struct WhitelistStatus {\n uint64 expirationTimestamp;\n uint192 indefiniteWhitelistCount;\n }\n\n mapping(bytes32 => mapping(address => WhitelistStatus))\n internal serviceIdToUserToWhitelistStatus;\n\n mapping(bytes32 => mapping(address => mapping(address => bool)))\n internal serviceIdToUserToSetterToIndefiniteWhitelistStatus;\n\n /// @notice Extends the expiration of the temporary whitelist of the user\n /// for the service\n /// @param serviceId Service ID\n /// @param user User address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function _extendWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) internal {\n require(\n expirationTimestamp >\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .expirationTimestamp,\n \"Does not extend expiration\"\n );\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .expirationTimestamp = expirationTimestamp;\n }\n\n /// @notice Sets the expiration of the temporary whitelist of the user for\n /// the service\n /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration\n /// @param serviceId Service ID\n /// @param user User address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function _setWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) internal {\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .expirationTimestamp = expirationTimestamp;\n }\n\n /// @notice Sets the indefinite whitelist status of the user for the\n /// service\n /// @dev As long as at least there is at least one account that has set the\n /// indefinite whitelist status of the user for the service as true, the\n /// user will be considered whitelisted\n /// @param serviceId Service ID\n /// @param user User address\n /// @param status Indefinite whitelist status\n function _setIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n bool status\n ) internal returns (uint192 indefiniteWhitelistCount) {\n indefiniteWhitelistCount = serviceIdToUserToWhitelistStatus[serviceId][\n user\n ].indefiniteWhitelistCount;\n if (\n status &&\n !serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][\n user\n ][msg.sender]\n ) {\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\n msg.sender\n ] = true;\n indefiniteWhitelistCount++;\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\n } else if (\n !status &&\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\n msg.sender\n ]\n ) {\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\n msg.sender\n ] = false;\n indefiniteWhitelistCount--;\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\n }\n }\n\n /// @notice Revokes the indefinite whitelist status granted to the user for\n /// the service by a specific account\n /// @param serviceId Service ID\n /// @param user User address\n /// @param setter Setter of the indefinite whitelist status\n function _revokeIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n address setter\n ) internal returns (bool revoked, uint192 indefiniteWhitelistCount) {\n indefiniteWhitelistCount = serviceIdToUserToWhitelistStatus[serviceId][\n user\n ].indefiniteWhitelistCount;\n if (\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\n setter\n ]\n ) {\n serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][\n setter\n ] = false;\n indefiniteWhitelistCount--;\n serviceIdToUserToWhitelistStatus[serviceId][user]\n .indefiniteWhitelistCount = indefiniteWhitelistCount;\n revoked = true;\n }\n }\n\n /// @notice Returns if the user is whitelised to use the service\n /// @param serviceId Service ID\n /// @param user User address\n /// @return isWhitelisted If the user is whitelisted\n function userIsWhitelisted(bytes32 serviceId, address user)\n internal\n view\n returns (bool isWhitelisted)\n {\n WhitelistStatus\n storage whitelistStatus = serviceIdToUserToWhitelistStatus[\n serviceId\n ][user];\n return\n whitelistStatus.indefiniteWhitelistCount > 0 ||\n whitelistStatus.expirationTimestamp > block.timestamp;\n }\n}\n" + }, + "contracts/whitelist/WhitelistRoles.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interfaces/IWhitelistRoles.sol\";\n\n/// @title Contract to be inherited by Whitelist contracts that will use\n/// generic AccessControlRegistry roles\ncontract WhitelistRoles is IWhitelistRoles {\n // There are four roles implemented in this contract:\n // Root\n // └── (1) Admin (can grant and revoke the roles below)\n // ├── (2) Whitelist expiration extender\n // ├── (3) Whitelist expiration setter\n // └── (4) Indefinite whitelister\n // Their IDs are derived from the descriptions below. Refer to\n // AccessControlRegistry for more information.\n // To clarify, the root role of the manager is the admin of (1), while (1)\n // is the admin of (2), (3) and (4). So (1) is more of a \"contract admin\",\n // while the `adminRole` used in AccessControl and AccessControlRegistry\n // refers to a more general adminship relationship between roles.\n\n /// @notice Whitelist expiration extender role description\n string\n public constant\n override WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION =\n \"Whitelist expiration extender\";\n\n /// @notice Whitelist expiration setter role description\n string\n public constant\n override WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION =\n \"Whitelist expiration setter\";\n\n /// @notice Indefinite whitelister role description\n\n string public constant override INDEFINITE_WHITELISTER_ROLE_DESCRIPTION =\n \"Indefinite whitelister\";\n\n bytes32\n internal constant WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH =\n keccak256(\n abi.encodePacked(WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION)\n );\n\n bytes32\n internal constant WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH =\n keccak256(\n abi.encodePacked(WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION)\n );\n\n bytes32 internal constant INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH =\n keccak256(abi.encodePacked(INDEFINITE_WHITELISTER_ROLE_DESCRIPTION));\n}\n" + }, + "contracts/whitelist/WhitelistRolesWithAirnode.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./WhitelistRoles.sol\";\nimport \"../access-control-registry/AccessControlRegistryAdminned.sol\";\nimport \"./interfaces/IWhitelistRolesWithAirnode.sol\";\nimport \"../access-control-registry/interfaces/IAccessControlRegistry.sol\";\n\n/// @title Contract to be inherited by Whitelist contracts that will use\n/// roles where each individual Airnode address is its own manager\ncontract WhitelistRolesWithAirnode is\n WhitelistRoles,\n AccessControlRegistryAdminned,\n IWhitelistRolesWithAirnode\n{\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription\n )\n AccessControlRegistryAdminned(\n _accessControlRegistry,\n _adminRoleDescription\n )\n {}\n\n /// @notice Derives the admin role for the Airnode\n /// @param airnode Airnode address\n /// @return adminRole Admin role\n function deriveAdminRole(address airnode)\n external\n view\n override\n returns (bytes32 adminRole)\n {\n adminRole = _deriveAdminRole(airnode);\n }\n\n /// @notice Derives the whitelist expiration extender role for the Airnode\n /// @param airnode Airnode address\n /// @return whitelistExpirationExtenderRole Whitelist expiration extender\n /// role\n function deriveWhitelistExpirationExtenderRole(address airnode)\n public\n view\n override\n returns (bytes32 whitelistExpirationExtenderRole)\n {\n whitelistExpirationExtenderRole = _deriveRole(\n _deriveAdminRole(airnode),\n WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH\n );\n }\n\n /// @notice Derives the whitelist expiration setter role for the Airnode\n /// @param airnode Airnode address\n /// @return whitelistExpirationSetterRole Whitelist expiration setter role\n function deriveWhitelistExpirationSetterRole(address airnode)\n public\n view\n override\n returns (bytes32 whitelistExpirationSetterRole)\n {\n whitelistExpirationSetterRole = _deriveRole(\n _deriveAdminRole(airnode),\n WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH\n );\n }\n\n /// @notice Derives the indefinite whitelister role for the Airnode\n /// @param airnode Airnode address\n /// @return indefiniteWhitelisterRole Indefinite whitelister role\n function deriveIndefiniteWhitelisterRole(address airnode)\n public\n view\n override\n returns (bytes32 indefiniteWhitelisterRole)\n {\n indefiniteWhitelisterRole = _deriveRole(\n _deriveAdminRole(airnode),\n INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH\n );\n }\n\n /// @dev Returns if the account has the whitelist expiration extender role\n /// or is the Airnode address\n /// @param airnode Airnode address\n /// @param account Account address\n /// @return If the account has the whitelist extender role or is the\n /// Airnode address\n function hasWhitelistExpirationExtenderRoleOrIsAirnode(\n address airnode,\n address account\n ) internal view returns (bool) {\n return\n airnode == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n deriveWhitelistExpirationExtenderRole(airnode),\n account\n );\n }\n\n /// @dev Returns if the account has the whitelist expriation setter role or\n /// is the Airnode address\n /// @param airnode Airnode address\n /// @param account Account address\n /// @return If the account has the whitelist setter role or is the Airnode\n /// address\n function hasWhitelistExpirationSetterRoleOrIsAirnode(\n address airnode,\n address account\n ) internal view returns (bool) {\n return\n airnode == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n deriveWhitelistExpirationSetterRole(airnode),\n account\n );\n }\n\n /// @dev Returns if the account has the indefinite whitelister role or is the\n /// Airnode address\n /// @param airnode Airnode address\n /// @param account Account address\n /// @return If the account has the indefinite whitelister role or is the\n /// Airnode addrss\n function hasIndefiniteWhitelisterRoleOrIsAirnode(\n address airnode,\n address account\n ) internal view returns (bool) {\n return\n airnode == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n deriveIndefiniteWhitelisterRole(airnode),\n account\n );\n }\n}\n" + }, + "contracts/whitelist/WhitelistRolesWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./WhitelistRoles.sol\";\nimport \"../access-control-registry/AccessControlRegistryAdminnedWithManager.sol\";\nimport \"./interfaces/IWhitelistRolesWithManager.sol\";\nimport \"../access-control-registry/interfaces/IAccessControlRegistry.sol\";\n\n/// @title Contract to be inherited by Whitelist contracts that will use\n/// roles where there is a single manager\ncontract WhitelistRolesWithManager is\n WhitelistRoles,\n AccessControlRegistryAdminnedWithManager,\n IWhitelistRolesWithManager\n{\n // Since there will be a single manager, we can derive the roles beforehand\n\n /// @notice Whitelist expiration extender role\n bytes32 public immutable override whitelistExpirationExtenderRole;\n\n /// @notice Whitelist expiration setter role\n bytes32 public immutable override whitelistExpirationSetterRole;\n\n /// @notice Indefinite whitelister role\n bytes32 public immutable override indefiniteWhitelisterRole;\n\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n /// @param _manager Manager address\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription,\n address _manager\n )\n AccessControlRegistryAdminnedWithManager(\n _accessControlRegistry,\n _adminRoleDescription,\n _manager\n )\n {\n whitelistExpirationExtenderRole = _deriveRole(\n adminRole,\n WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH\n );\n whitelistExpirationSetterRole = _deriveRole(\n adminRole,\n WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH\n );\n indefiniteWhitelisterRole = _deriveRole(\n adminRole,\n INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH\n );\n }\n\n /// @dev Returns if the account has the whitelist expiration extender role\n /// or is the manager\n /// @param account Account address\n /// @return If the account has the whitelist extender role or is the\n /// manager\n function hasWhitelistExpirationExtenderRoleOrIsManager(address account)\n internal\n view\n returns (bool)\n {\n return\n manager == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n whitelistExpirationExtenderRole,\n account\n );\n }\n\n /// @dev Returns if the account has the whitelist expriation setter role or\n /// is the manager\n /// @param account Account address\n /// @return If the account has the whitelist setter role or is the\n /// manager\n function hasWhitelistExpirationSetterRoleOrIsManager(address account)\n internal\n view\n returns (bool)\n {\n return\n manager == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n whitelistExpirationSetterRole,\n account\n );\n }\n\n /// @dev Returns if the account has the indefinite whitelister role or is the\n /// manager\n /// @param account Account address\n /// @return If the account has the indefinite whitelister role or is the\n /// manager\n function hasIndefiniteWhitelisterRoleOrIsManager(address account)\n internal\n view\n returns (bool)\n {\n return\n manager == account ||\n IAccessControlRegistry(accessControlRegistry).hasRole(\n indefiniteWhitelisterRole,\n account\n );\n }\n}\n" + }, + "contracts/whitelist/WhitelistWithManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./Whitelist.sol\";\nimport \"./WhitelistRolesWithManager.sol\";\nimport \"./interfaces/IWhitelistWithManager.sol\";\n\n/// @title Contract to be inherited by Whitelist contracts that are controlled\n/// by a manager\ncontract WhitelistWithManager is\n Whitelist,\n WhitelistRolesWithManager,\n IWhitelistWithManager\n{\n /// @param _accessControlRegistry AccessControlRegistry contract address\n /// @param _adminRoleDescription Admin role description\n /// @param _manager Manager address\n constructor(\n address _accessControlRegistry,\n string memory _adminRoleDescription,\n address _manager\n )\n WhitelistRolesWithManager(\n _accessControlRegistry,\n _adminRoleDescription,\n _manager\n )\n {}\n\n /// @notice Extends the expiration of the temporary whitelist of `user` to\n /// be able to use the service with `serviceId` if the sender has the\n /// whitelist expiration extender role\n /// @param serviceId Service ID\n /// @param user User address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function extendWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationExtenderRoleOrIsManager(msg.sender),\n \"Cannot extend expiration\"\n );\n require(serviceId != bytes32(0), \"Service ID zero\");\n require(user != address(0), \"User address zero\");\n _extendWhitelistExpiration(serviceId, user, expirationTimestamp);\n emit ExtendedWhitelistExpiration(\n serviceId,\n user,\n msg.sender,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the expiration of the temporary whitelist of `user` to be\n /// able to use the service with `serviceId` if the sender has the\n /// whitelist expiration setter role\n /// @param serviceId Service ID\n /// @param user User address\n /// @param expirationTimestamp Timestamp at which the temporary whitelist\n /// will expire\n function setWhitelistExpiration(\n bytes32 serviceId,\n address user,\n uint64 expirationTimestamp\n ) external override {\n require(\n hasWhitelistExpirationSetterRoleOrIsManager(msg.sender),\n \"Cannot set expiration\"\n );\n require(serviceId != bytes32(0), \"Service ID zero\");\n require(user != address(0), \"User address zero\");\n _setWhitelistExpiration(serviceId, user, expirationTimestamp);\n emit SetWhitelistExpiration(\n serviceId,\n user,\n msg.sender,\n expirationTimestamp\n );\n }\n\n /// @notice Sets the indefinite whitelist status of `user` to be able to\n /// use the service with `serviceId` if the sender has the indefinite\n /// whitelister role\n /// @param serviceId Service ID\n /// @param user User address\n /// @param status Indefinite whitelist status\n function setIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n bool status\n ) external override {\n require(\n hasIndefiniteWhitelisterRoleOrIsManager(msg.sender),\n \"Cannot set indefinite status\"\n );\n require(serviceId != bytes32(0), \"Service ID zero\");\n require(user != address(0), \"User address zero\");\n uint192 indefiniteWhitelistCount = _setIndefiniteWhitelistStatus(\n serviceId,\n user,\n status\n );\n emit SetIndefiniteWhitelistStatus(\n serviceId,\n user,\n msg.sender,\n status,\n indefiniteWhitelistCount\n );\n }\n\n /// @notice Revokes the indefinite whitelist status granted by a specific\n /// account that no longer has the indefinite whitelister role\n /// @param serviceId Service ID\n /// @param user User address\n /// @param setter Setter of the indefinite whitelist status\n function revokeIndefiniteWhitelistStatus(\n bytes32 serviceId,\n address user,\n address setter\n ) external override {\n require(\n !hasIndefiniteWhitelisterRoleOrIsManager(setter),\n \"setter can set indefinite status\"\n );\n (\n bool revoked,\n uint192 indefiniteWhitelistCount\n ) = _revokeIndefiniteWhitelistStatus(serviceId, user, setter);\n if (revoked) {\n emit RevokedIndefiniteWhitelistStatus(\n serviceId,\n user,\n setter,\n msg.sender,\n indefiniteWhitelistCount\n );\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/packages/airnode-protocol/deployments/references.json b/packages/airnode-protocol/deployments/references.json index 18dfa3f0d4..dd173ec7ea 100644 --- a/packages/airnode-protocol/deployments/references.json +++ b/packages/airnode-protocol/deployments/references.json @@ -21,6 +21,7 @@ "1285": "moonriver", "1287": "moonbeam-testnet", "1442": "polygon-zkevm-goerli-testnet", + "1890": "lightlink", "1891": "lightlink-goerli-testnet", "2001": "milkomeda-c1", "4002": "fantom-testnet", @@ -68,6 +69,7 @@ "1285": "0x92E5125adF385d86beDb950793526106143b6Df1", "1287": "0x92E5125adF385d86beDb950793526106143b6Df1", "1442": "0x92E5125adF385d86beDb950793526106143b6Df1", + "1890": "0x92E5125adF385d86beDb950793526106143b6Df1", "1891": "0x92E5125adF385d86beDb950793526106143b6Df1", "2001": "0x92E5125adF385d86beDb950793526106143b6Df1", "4002": "0x92E5125adF385d86beDb950793526106143b6Df1", @@ -115,6 +117,7 @@ "1285": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "1287": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "1442": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "1890": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "1891": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "2001": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "4002": "0xf18c105D0375E80980e4EED829a4A68A539E6178", @@ -162,6 +165,7 @@ "1285": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "1287": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "1442": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "1890": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "1891": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "2001": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "4002": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", @@ -209,6 +213,7 @@ "1285": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "1287": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "1442": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "1890": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "1891": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "2001": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "4002": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", @@ -319,6 +324,10 @@ "chainId": 1442, "name": "polygon-zkevm-goerli-testnet" }, + "1890": { + "chainId": 1890, + "name": "lightlink" + }, "1891": { "chainId": 1891, "name": "lightlink-goerli-testnet" From 031c815452c029cb3d7d165cc8963a4b28fdc1fe Mon Sep 17 00:00:00 2001 From: Vansh Wassan <007blackhacker@gmail.com> Date: Mon, 11 Dec 2023 03:42:47 +0530 Subject: [PATCH 4/9] Updated api3/chains package --- packages/airnode-protocol/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/airnode-protocol/package.json b/packages/airnode-protocol/package.json index 351d2e09f1..d06b13e8fd 100644 --- a/packages/airnode-protocol/package.json +++ b/packages/airnode-protocol/package.json @@ -29,7 +29,7 @@ "write-example-env-file": "hardhat run scripts/write-example-env-file.ts" }, "devDependencies": { - "@api3/chains": "^4.1.0", + "@api3/chains": "^4.1.2", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "^3.1.7", "@nomiclabs/hardhat-waffle": "^2.0.6", From 97c702b8b457934231a39427622bc5b97d80ff44 Mon Sep 17 00:00:00 2001 From: Vansh Wassan <007blackhacker@gmail.com> Date: Mon, 18 Dec 2023 18:28:02 +0530 Subject: [PATCH 5/9] package version revert --- packages/airnode-protocol/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/airnode-protocol/package.json b/packages/airnode-protocol/package.json index d06b13e8fd..d432160a26 100644 --- a/packages/airnode-protocol/package.json +++ b/packages/airnode-protocol/package.json @@ -29,7 +29,7 @@ "write-example-env-file": "hardhat run scripts/write-example-env-file.ts" }, "devDependencies": { - "@api3/chains": "^4.1.2", + "@api3/chains": "^4.1.1", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "^3.1.7", "@nomiclabs/hardhat-waffle": "^2.0.6", From 95113422b983d1ed54d64cc75fae6802c5536086 Mon Sep 17 00:00:00 2001 From: Vansh Wassan <007blackhacker@gmail.com> Date: Mon, 18 Dec 2023 18:36:05 +0530 Subject: [PATCH 6/9] package version revert --- packages/airnode-protocol/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/airnode-protocol/package.json b/packages/airnode-protocol/package.json index d432160a26..351d2e09f1 100644 --- a/packages/airnode-protocol/package.json +++ b/packages/airnode-protocol/package.json @@ -29,7 +29,7 @@ "write-example-env-file": "hardhat run scripts/write-example-env-file.ts" }, "devDependencies": { - "@api3/chains": "^4.1.1", + "@api3/chains": "^4.1.0", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "^3.1.7", "@nomiclabs/hardhat-waffle": "^2.0.6", From 659fe8ccdb18e41c6ec14306891374c0cf8bf436 Mon Sep 17 00:00:00 2001 From: Vansh Wassan <007blackhacker@gmail.com> Date: Fri, 12 Jan 2024 19:11:25 +0530 Subject: [PATCH 7/9] `@api3/chains` version bump --- packages/airnode-protocol/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/airnode-protocol/package.json b/packages/airnode-protocol/package.json index bcbd880824..fb610c42c1 100644 --- a/packages/airnode-protocol/package.json +++ b/packages/airnode-protocol/package.json @@ -29,7 +29,7 @@ "write-example-env-file": "hardhat run scripts/write-example-env-file.ts" }, "devDependencies": { - "@api3/chains": "^4.1.1", + "@api3/chains": "^4.3.0", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "^3.1.7", "@nomiclabs/hardhat-waffle": "^2.0.6", From aaf72a2a8b995e045ba740671a280550bfa7ba9b Mon Sep 17 00:00:00 2001 From: Vansh Wassan <007blackhacker@gmail.com> Date: Sat, 13 Jan 2024 23:16:43 +0530 Subject: [PATCH 8/9] `yarn run bootstrap` & `yarn run build` --- yarn.lock | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/yarn.lock b/yarn.lock index eb1f3e1c4e..faa99cba50 100644 --- a/yarn.lock +++ b/yarn.lock @@ -35,6 +35,14 @@ viem "^1.19.11" zod "^3.22.4" +"@api3/chains@^4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@api3/chains/-/chains-4.3.0.tgz#97942268588e63ee030323f622f144eb2ec240a2" + integrity sha512-ME9Vun5enzz3WFmLNRj8lnRmW/zLYimu8KvoqoyZBVAdRDasSWF9FeuOcdQ42sc8l2GF48RuPQCvIhm905tVZg== + dependencies: + viem "^2.0.6" + zod "^3.22.4" + "@api3/commons@^0.5.0": version "0.5.0" resolved "https://registry.npmjs.org/@api3/commons/-/commons-0.5.0.tgz#d9ff9aba3a2da8cd7b678371550881e008c43a1c" @@ -5004,6 +5012,11 @@ abbrev@1.0.x: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" integrity sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q== +abitype@0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.10.0.tgz#d3504747cc81df2acaa6c460250ef7bc9219a77c" + integrity sha512-QvMHEUzgI9nPj9TWtUGnS2scas80/qaL5PBxGdwWhhvzqXfOph+IEiiiWrzuisu3U3JgDQVruW9oLbJoQ3oZ3A== + abitype@0.9.8: version "0.9.8" resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.8.tgz#1f120b6b717459deafd213dfbf3a3dd1bf10ae8c" @@ -15594,6 +15607,20 @@ viem@^1.19.11: isows "1.0.3" ws "8.13.0" +viem@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.0.6.tgz#1472054eb767c8e74db2e6fab11a8ad8db7387d0" + integrity sha512-u7P/RCHufWZW2x2d1MB9O9S9xAopXlWpWEThxfD7FKKzyFGw0lN3QYC3FG0KHKziRDieeu4lkVzAkdag7W+S6g== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@scure/bip32" "1.3.2" + "@scure/bip39" "1.2.1" + abitype "0.10.0" + isows "1.0.3" + ws "8.13.0" + vizion@~2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/vizion/-/vizion-2.2.1.tgz#04201ea45ffd145d5b5210e385a8f35170387fb2" From a729951c6efd2d50ffd03c04d285f08b2e5b83b7 Mon Sep 17 00:00:00 2001 From: Vansh Wassan <007blackhacker@gmail.com> Date: Sun, 14 Jan 2024 00:09:31 +0530 Subject: [PATCH 9/9] Updated `@api3/chains` in `airnode-node` package --- packages/airnode-node/package.json | 2 +- yarn.lock | 27 --------------------------- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/packages/airnode-node/package.json b/packages/airnode-node/package.json index 8d63dc3e09..4ab133c80f 100644 --- a/packages/airnode-node/package.json +++ b/packages/airnode-node/package.json @@ -29,7 +29,7 @@ "@api3/airnode-protocol": "^0.13.0", "@api3/airnode-utilities": "^0.13.0", "@api3/airnode-validator": "^0.13.0", - "@api3/chains": "^4.1.1", + "@api3/chains": "^4.3.0", "@api3/commons": "^0.5.0", "@api3/ois": "2.3.1", "@api3/promise-utils": "^0.4.0", diff --git a/yarn.lock b/yarn.lock index faa99cba50..e958c36c74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,14 +27,6 @@ dependencies: "@openzeppelin/contracts" "4.8.2" -"@api3/chains@^4.1.1": - version "4.1.1" - resolved "https://registry.yarnpkg.com/@api3/chains/-/chains-4.1.1.tgz#07b57a79813f9f6dbd4c79d8f1ffd1d718927aa7" - integrity sha512-+XyFaWAQNXNJjMKXNFgkYu335icMIk7i3MEjlw925oazQ0n7mnP6LVbsPIdYxdgIa0WwJTCmlbS+r9YcM7hpmQ== - dependencies: - viem "^1.19.11" - zod "^3.22.4" - "@api3/chains@^4.3.0": version "4.3.0" resolved "https://registry.yarnpkg.com/@api3/chains/-/chains-4.3.0.tgz#97942268588e63ee030323f622f144eb2ec240a2" @@ -5017,11 +5009,6 @@ abitype@0.10.0: resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.10.0.tgz#d3504747cc81df2acaa6c460250ef7bc9219a77c" integrity sha512-QvMHEUzgI9nPj9TWtUGnS2scas80/qaL5PBxGdwWhhvzqXfOph+IEiiiWrzuisu3U3JgDQVruW9oLbJoQ3oZ3A== -abitype@0.9.8: - version "0.9.8" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.8.tgz#1f120b6b717459deafd213dfbf3a3dd1bf10ae8c" - integrity sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ== - abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -15593,20 +15580,6 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -viem@^1.19.11: - version "1.19.13" - resolved "https://registry.yarnpkg.com/viem/-/viem-1.19.13.tgz#3a018720bd2abf54a039c751fc2bcd473838c523" - integrity sha512-DizIwJAecLedI+nq6c5LIqCLAnYXUhQX5BnH6o1H2ln6isPyJVf+v4H1IfMlRHgR5KRlC+wGI/mCjarr3tW6eg== - dependencies: - "@adraffy/ens-normalize" "1.10.0" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@scure/bip32" "1.3.2" - "@scure/bip39" "1.2.1" - abitype "0.9.8" - isows "1.0.3" - ws "8.13.0" - viem@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/viem/-/viem-2.0.6.tgz#1472054eb767c8e74db2e6fab11a8ad8db7387d0"