diff --git a/.changeset/breezy-timers-wash.md b/.changeset/breezy-timers-wash.md new file mode 100644 index 0000000000..2a2fced47a --- /dev/null +++ b/.changeset/breezy-timers-wash.md @@ -0,0 +1,6 @@ +--- +'@api3/airnode-node': minor +'@api3/airnode-protocol': minor +--- + +BREAKING CHANGE: Remove chainNames and networks from references.json and instead use api3/chains diff --git a/.changeset/curly-mails-dream.md b/.changeset/curly-mails-dream.md deleted file mode 100644 index dc86d9fdc1..0000000000 --- a/.changeset/curly-mails-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@api3/airnode-deployer': patch ---- - -Bump dev dependency @octokit/core to v5 diff --git a/.changeset/eighty-items-fail.md b/.changeset/eighty-items-fail.md deleted file mode 100644 index a77c37b9a6..0000000000 --- a/.changeset/eighty-items-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@api3/airnode-node': patch ---- - -Harmonize HTTP gateway response object when encoding fails compared to when it succeeds diff --git a/.changeset/large-mangos-end.md b/.changeset/friendly-ghosts-buy.md similarity index 100% rename from .changeset/large-mangos-end.md rename to .changeset/friendly-ghosts-buy.md diff --git a/.changeset/healthy-jeans-cheer.md b/.changeset/healthy-jeans-cheer.md new file mode 100644 index 0000000000..b9021114dc --- /dev/null +++ b/.changeset/healthy-jeans-cheer.md @@ -0,0 +1,5 @@ +--- +'@api3/airnode-deployer': minor +--- + +Increase OEV gateway memory limit diff --git a/.changeset/lazy-tables-lick.md b/.changeset/khaki-dragons-act.md similarity index 100% rename from .changeset/lazy-tables-lick.md rename to .changeset/khaki-dragons-act.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 diff --git a/.changeset/many-wombats-join.md b/.changeset/many-wombats-join.md new file mode 100644 index 0000000000..8599b98ad9 --- /dev/null +++ b/.changeset/many-wombats-join.md @@ -0,0 +1,5 @@ +--- +'@api3/airnode-examples': patch +--- + +Use api3/chains instead of airnode-protocol for chain names diff --git a/.changeset/mighty-parents-melt.md b/.changeset/mighty-parents-melt.md new file mode 100644 index 0000000000..35b993ad7e --- /dev/null +++ b/.changeset/mighty-parents-melt.md @@ -0,0 +1,6 @@ +--- +'@api3/airnode-examples': minor +'@api3/airnode-node': minor +--- + +Support OIS processing v2 diff --git a/.changeset/orange-dingos-trade.md b/.changeset/orange-dingos-trade.md new file mode 100644 index 0000000000..a904df81d1 --- /dev/null +++ b/.changeset/orange-dingos-trade.md @@ -0,0 +1,8 @@ +--- +'@api3/airnode-validator': minor +'@api3/airnode-protocol': minor +'@api3/airnode-adapter': minor +'@api3/airnode-node': minor +--- + +Bump axios and @api3 deps diff --git a/.changeset/serious-bobcats-begin.md b/.changeset/serious-bobcats-begin.md deleted file mode 100644 index 9456d76813..0000000000 --- a/.changeset/serious-bobcats-begin.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@api3/airnode-deployer': patch -'@api3/airnode-protocol': patch -'@api3/airnode-node': patch ---- - -Update to @smithy package for aws-sdk diff --git a/.changeset/silver-cobras-dream.md b/.changeset/silver-cobras-dream.md new file mode 100644 index 0000000000..198d009a87 --- /dev/null +++ b/.changeset/silver-cobras-dream.md @@ -0,0 +1,5 @@ +--- +'@api3/airnode-protocol': minor +--- + +Remove boba-avalanche as it has been shut down diff --git a/.changeset/silver-horses-live.md b/.changeset/silver-horses-live.md deleted file mode 100644 index a845151cc8..0000000000 --- a/.changeset/silver-horses-live.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/soft-sloths-brake.md b/.changeset/soft-sloths-brake.md new file mode 100644 index 0000000000..fc51695029 --- /dev/null +++ b/.changeset/soft-sloths-brake.md @@ -0,0 +1,6 @@ +--- +'@api3/airnode-deployer': minor +'@api3/airnode-node': minor +--- + +BREAKING CHANGE: the OEV gateway interface has changed in the following ways: `api3ServerV1` has replaced `dapiServerAddress` and `templateId` has replaced `endpointId` and `encodedParameters`. diff --git a/.changeset/spotty-mice-type.md b/.changeset/spotty-mice-type.md new file mode 100644 index 0000000000..1807caa796 --- /dev/null +++ b/.changeset/spotty-mice-type.md @@ -0,0 +1,5 @@ +--- +'@api3/airnode-node': patch +--- + +New Airnode version changeset initialization diff --git a/.github/workflows/protocol-verify.yml b/.github/workflows/protocol-verify.yml index 25cb81bc9a..74b0a17c5a 100644 --- a/.github/workflows/protocol-verify.yml +++ b/.github/workflows/protocol-verify.yml @@ -6,6 +6,7 @@ on: - master paths: - 'packages/airnode-protocol/**' + - '!packages/airnode-protocol/package.json' types: [opened, synchronize, reopened] env: @@ -16,8 +17,6 @@ jobs: pre-build: name: Prepare build environment runs-on: ubuntu-latest - # Don't run twice for a push within an internal PR - if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository steps: - name: Clone airnode uses: actions/checkout@v3 @@ -39,8 +38,6 @@ jobs: build: name: Build Protocol runs-on: ubuntu-latest - # Don't run twice for a push within an internal PR - if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository needs: pre-build steps: - uses: actions/cache@v3 diff --git a/.solhint.json b/.solhint.json index da7fa7aab2..9b4673865e 100644 --- a/.solhint.json +++ b/.solhint.json @@ -5,6 +5,8 @@ "func-visibility": ["warn", { "ignoreConstructors": true }], "not-rely-on-time": "off", "no-empty-blocks": "off", - "no-global-import": "off" + "no-global-import": "off", + "custom-errors": "off", + "immutable-vars-naming": "off" } } diff --git a/docker/Dockerfile b/docker/Dockerfile index 9573d4c33f..c3e129f7a5 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -7,7 +7,7 @@ ENV appDir="/app" \ CI="true" RUN apk add --update --no-cache git rsync docker $([ $(arch) == "aarch64" ] && echo "python3 make g++") && \ - yarn global add npm && \ + yarn global add npm@^9.8.1 && \ # Download both solidity compilers as per: https://github.com/nomiclabs/hardhat/issues/1280#issuecomment-949822371 mkdir -p /root/.cache/hardhat-nodejs/compilers-v2/wasm && \ wget -O /root/.cache/hardhat-nodejs/compilers-v2/wasm/soljson-v0.8.9+commit.e5eed63a.js https://solc-bin.ethereum.org/wasm/soljson-v0.8.9+commit.e5eed63a.js && \ diff --git a/docker/scripts/github.ts b/docker/scripts/github.ts index 0047d19bdc..f65ea7e502 100644 --- a/docker/scripts/github.ts +++ b/docker/scripts/github.ts @@ -6,7 +6,7 @@ import { runCommand } from './utils'; const OWNER = 'api3dao'; const REPOSITORY = 'airnode'; -const TEAM = 'airnode'; +const TEAM = 'airnode-releasers'; const initializeOctokit = () => { const githubToken = process.env.GITHUB_TOKEN; diff --git a/package.json b/package.json index 75d2a2ebae..23b0217b24 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,7 @@ "test:protocol:verify-local": "cd packages/airnode-protocol && yarn run test:verify-local", "test:node": "(cd packages/airnode-node && yarn run test)", "test:node:watch": "cd packages/airnode-node && yarn run test:watch", + "test:release": "ts-node scripts/test-release.ts", "test:utilities": "(cd packages/airnode-utilities && yarn run test)", "test:validator": "(cd packages/airnode-validator && yarn run test)", "update-ois-version": "ts-node scripts/update-ois-version.ts" @@ -107,28 +108,28 @@ "@api3/promise-utils": "^0.4.0", "@changesets/changelog-github": "^0.4.8", "@changesets/cli": "^2.26.2", - "@octokit/core": "^5.0.0", - "@types/libsodium-wrappers": "^0.7.10", - "@types/node": "^18.16.19", - "@typescript-eslint/eslint-plugin": "^5.61.0", - "@typescript-eslint/parser": "^5.61.0", - "@vercel/ncc": "^0.36.1", - "axios": "^1.4.0", + "@octokit/core": "^5.0.1", + "@types/libsodium-wrappers": "^0.7.12", + "@types/node": "^18.18.7", + "@typescript-eslint/eslint-plugin": "^5.62.0", + "@typescript-eslint/parser": "^5.62.0", + "@vercel/ncc": "^0.38.1", + "axios": "^1.6.0", "comment-json": "^4.2.3", - "eslint": "^8.44.0", + "eslint": "^8.52.0", "eslint-plugin-functional": "^5.0.8", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jest": "^27.2.2", - "fast-glob": "^3.3.0", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-jest": "^27.6.0", + "fast-glob": "^3.3.1", "husky": "^8.0.3", - "lerna": "^7.1.1", - "libsodium-wrappers": "^0.7.11", - "prettier": "^2.8.8", + "lerna": "^7.4.1", + "libsodium-wrappers": "^0.7.13", + "prettier": "^3.0.3", "prettier-plugin-solidity": "^1.1.3", - "rimraf": "^5.0.1", - "solhint": "^3.4.1", + "rimraf": "^5.0.5", + "solhint": "^3.6.2", "ts-node": "^10.9.1", - "typescript": "^5.1.6", + "typescript": "^5.2.2", "yargs": "^17.7.2" } } diff --git a/packages/airnode-abi/CHANGELOG.md b/packages/airnode-abi/CHANGELOG.md index 093ee49a7e..d7e3fc2d6c 100644 --- a/packages/airnode-abi/CHANGELOG.md +++ b/packages/airnode-abi/CHANGELOG.md @@ -1,5 +1,7 @@ # @api3/airnode-abi +## 0.13.0 + ## 0.12.0 ## 0.11.0 diff --git a/packages/airnode-abi/package.json b/packages/airnode-abi/package.json index 706106e080..8299243696 100644 --- a/packages/airnode-abi/package.json +++ b/packages/airnode-abi/package.json @@ -1,7 +1,7 @@ { "name": "@api3/airnode-abi", "license": "MIT", - "version": "0.12.0", + "version": "0.13.0", "private": false, "main": "dist/index", "types": "dist/index", @@ -21,9 +21,9 @@ "lodash": "^4.17.21" }, "devDependencies": { - "@types/lodash": "^4.14.195", - "jest": "^29.6.0", - "rimraf": "^5.0.1", - "typescript": "^5.1.6" + "@types/lodash": "^4.14.200", + "jest": "^29.7.0", + "rimraf": "^5.0.5", + "typescript": "^5.2.2" } } diff --git a/packages/airnode-adapter/CHANGELOG.md b/packages/airnode-adapter/CHANGELOG.md index 0648d7afa9..0833521ee4 100644 --- a/packages/airnode-adapter/CHANGELOG.md +++ b/packages/airnode-adapter/CHANGELOG.md @@ -1,5 +1,17 @@ # @api3/airnode-adapter +## 0.13.0 + +### Minor Changes + +- [#1888](https://github.com/api3dao/airnode/pull/1888) [`1da62631`](https://github.com/api3dao/airnode/commit/1da62631905cf4b49266f248c8c385b5106d4c4d) Thanks [@dcroote](https://github.com/dcroote)! - Bump OIS to v2.2.0 and make operationParameter optional within endpoint parameters + +### Patch Changes + +- [#1893](https://github.com/api3dao/airnode/pull/1893) [`cefc5e4a`](https://github.com/api3dao/airnode/commit/cefc5e4abcc0f10a9b0b84b9bf55af2f34ffe1bd) Thanks [@dcroote](https://github.com/dcroote)! - Bump ois to v2.2.1 + +- [#1825](https://github.com/api3dao/airnode/pull/1825) [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3) Thanks [@renovate](https://github.com/apps/renovate)! - Apply prettier v3 formatting + ## 0.12.0 ### Minor Changes diff --git a/packages/airnode-adapter/package.json b/packages/airnode-adapter/package.json index 53e60c918e..fd45ca0ec6 100644 --- a/packages/airnode-adapter/package.json +++ b/packages/airnode-adapter/package.json @@ -1,7 +1,7 @@ { "name": "@api3/airnode-adapter", "license": "MIT", - "version": "0.12.0", + "version": "0.13.0", "private": false, "main": "dist/index", "types": "dist/index", @@ -19,25 +19,25 @@ "test:watch": "yarn test:ts --watch" }, "dependencies": { - "@api3/ois": "2.1.0", + "@api3/ois": "2.3.1", "@api3/promise-utils": "^0.4.0", - "axios": "^1.4.0", - "bignumber.js": "^9.1.1", + "axios": "^1.6.2", + "bignumber.js": "^9.1.2", "ethers": "^5.7.2", "lodash": "^4.17.21" }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-waffle": "^2.0.6", - "@types/chai": "^4.3.5", - "@types/lodash": "^4.14.195", - "@types/mocha": "^10.0.1", - "chai": "^4.3.7", + "@types/chai": "^4.3.9", + "@types/lodash": "^4.14.200", + "@types/mocha": "^10.0.3", + "chai": "^4.3.10", "ethereum-waffle": "^4.0.10", "hardhat": "^2.14.1", - "jest": "^29.6.0", - "rimraf": "^5.0.1", + "jest": "^29.7.0", + "rimraf": "^5.0.5", "ts-jest": "^29.1.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } } diff --git a/packages/airnode-adapter/src/request-building/parameters.test.ts b/packages/airnode-adapter/src/request-building/parameters.test.ts index a1eb9ad923..5c7aa8f94c 100644 --- a/packages/airnode-adapter/src/request-building/parameters.test.ts +++ b/packages/airnode-adapter/src/request-building/parameters.test.ts @@ -81,6 +81,33 @@ describe('fixed parameters', () => { headers: {}, }); }); + + it('ignores parameters without operationParameter', () => { + const ois = fixtures.buildOIS(); + ois.apiSpecifications.paths['/convert'].get!.parameters.push({ in: 'query', name: 'noOperationParameter' }); + const options = fixtures.buildCacheRequestOptions({ + ois, + parameters: { f: 'ETH', amount: '1', no_op: 'myValue' }, + }); + options.endpoint.parameters.push({ + name: 'no_op', + // operationParameter is absent + }); + options.operation.parameters.push({ name: 'noOperationParameter', in: 'query' }); + const res = parameters.buildParameters(options); + expect(res).toEqual({ + paths: {}, + query: { + // Expectedly absent: + // noOperationParameter: 'myValue', + access_key: 'super-secret-key', + amount: '1', + from: 'ETH', + to: 'USD', + }, + headers: {}, + }); + }); }); describe('user parameters', () => { diff --git a/packages/airnode-adapter/src/request-building/parameters.ts b/packages/airnode-adapter/src/request-building/parameters.ts index 35eacf1ce5..63848d6e9a 100644 --- a/packages/airnode-adapter/src/request-building/parameters.ts +++ b/packages/airnode-adapter/src/request-building/parameters.ts @@ -3,7 +3,7 @@ import * as authentication from './authentication'; import * as cookies from './cookies'; import { BuilderParameters, CachedBuildRequestOptions, RequestParameters } from '../types'; -function initalParameters(): BuilderParameters { +function initialParameters(): BuilderParameters { return { paths: {}, query: {}, @@ -49,7 +49,7 @@ function buildFixedParameters(options: CachedBuildRequestOptions): BuilderParame } return appendParameter(acc, target, name, parameter.value); - }, initalParameters()); + }, initialParameters()); } function buildUserParameters(options: CachedBuildRequestOptions): BuilderParameters { @@ -66,16 +66,19 @@ function buildUserParameters(options: CachedBuildRequestOptions): BuilderParamet // Double check that the parameter exists in the API specification const apiParameter = operation.parameters.find( - (p) => p.name === parameter.operationParameter.name && p.in === parameter.operationParameter.in + (p) => + parameter.operationParameter && + p.name === parameter.operationParameter.name && + p.in === parameter.operationParameter.in ); - if (!apiParameter) { + if (!apiParameter || !parameter.operationParameter) { return acc; } const { name, in: target } = parameter.operationParameter; return appendParameter(acc, target, name, parameters[key]); - }, initalParameters()); + }, initialParameters()); } export function buildParameters(options: CachedBuildRequestOptions): RequestParameters { diff --git a/packages/airnode-adapter/src/response-processing/extraction.ts b/packages/airnode-adapter/src/response-processing/extraction.ts index bc21ae7a05..ff7a621d5c 100644 --- a/packages/airnode-adapter/src/response-processing/extraction.ts +++ b/packages/airnode-adapter/src/response-processing/extraction.ts @@ -94,11 +94,13 @@ export function splitReservedParameters(parameters: ResponseReservedParameters): }); const reservedParameters: ResponseReservedParameters[] = range(typesLength).map((i) => - splitParams.reduce((acc, param) => { - if (!param.splitResult) return acc; - - return { ...acc, [param.name]: param.splitResult[i] }; - }, {} as any as ResponseReservedParameters) + splitParams.reduce( + (acc, param) => { + if (!param.splitResult) return acc; + return { ...acc, [param.name]: param.splitResult[i] }; + }, + {} as any as ResponseReservedParameters + ) ); return reservedParameters; diff --git a/packages/airnode-adapter/test/fixtures/ois.ts b/packages/airnode-adapter/test/fixtures/ois.ts index f4dbf6f198..5a487e0948 100644 --- a/packages/airnode-adapter/test/fixtures/ois.ts +++ b/packages/airnode-adapter/test/fixtures/ois.ts @@ -2,7 +2,7 @@ import { OIS } from '@api3/ois'; export function buildOIS(overrides?: Partial): OIS { return { - oisFormat: '2.1.0', + oisFormat: '2.3.1', version: '1.2.3', title: 'Currency Converter API', apiSpecifications: { diff --git a/packages/airnode-admin/CHANGELOG.md b/packages/airnode-admin/CHANGELOG.md index 5f5672da30..1efc93530f 100644 --- a/packages/airnode-admin/CHANGELOG.md +++ b/packages/airnode-admin/CHANGELOG.md @@ -1,5 +1,17 @@ # @api3/airnode-admin +## 0.13.0 + +### Patch Changes + +- [#1825](https://github.com/api3dao/airnode/pull/1825) [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3) Thanks [@renovate](https://github.com/apps/renovate)! - Apply prettier v3 formatting + +- Updated dependencies [[`87cee037`](https://github.com/api3dao/airnode/commit/87cee0372afc60acb141ad308d3664172f3cbdb6), [`1da62631`](https://github.com/api3dao/airnode/commit/1da62631905cf4b49266f248c8c385b5106d4c4d), [`d2e5a04b`](https://github.com/api3dao/airnode/commit/d2e5a04bf6e88de1888f044dfb171344171ba0ea), [`1d7e4b2f`](https://github.com/api3dao/airnode/commit/1d7e4b2fe4467cee05a6d5f4b34b772d377337df), [`cefc5e4a`](https://github.com/api3dao/airnode/commit/cefc5e4abcc0f10a9b0b84b9bf55af2f34ffe1bd), [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3)]: + - @api3/airnode-protocol@0.13.0 + - @api3/airnode-validator@0.13.0 + - @api3/airnode-utilities@0.13.0 + - @api3/airnode-abi@0.13.0 + ## 0.12.0 ### Patch Changes diff --git a/packages/airnode-admin/package.json b/packages/airnode-admin/package.json index b60f85534f..96de01415c 100644 --- a/packages/airnode-admin/package.json +++ b/packages/airnode-admin/package.json @@ -1,7 +1,7 @@ { "name": "@api3/airnode-admin", "license": "MIT", - "version": "0.12.0", + "version": "0.13.0", "private": false, "bin": { "airnode-admin": "./dist/bin/admin.js" @@ -24,23 +24,23 @@ "test:watch:debug": "jest \"implementation.test\" --selectProjects unit --watch" }, "dependencies": { - "@api3/airnode-abi": "^0.12.0", - "@api3/airnode-protocol": "^0.12.0", - "@api3/airnode-utilities": "^0.12.0", - "@api3/airnode-validator": "^0.12.0", + "@api3/airnode-abi": "^0.13.0", + "@api3/airnode-protocol": "^0.13.0", + "@api3/airnode-utilities": "^0.13.0", + "@api3/airnode-validator": "^0.13.0", "@api3/promise-utils": "^0.4.0", "ethers": "^5.7.2", "lodash": "^4.17.21", "yargs": "^17.7.2" }, "devDependencies": { - "@types/lodash": "^4.14.195", - "@types/node": "^18.16.19", - "@types/yargs": "^17.0.24", - "jest": "^29.6.0", - "rimraf": "^5.0.1", + "@types/lodash": "^4.14.200", + "@types/node": "^18.18.7", + "@types/yargs": "^17.0.29", + "jest": "^29.7.0", + "rimraf": "^5.0.5", "ts-jest": "^29.1.1", "ts-node": "^10.9.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } } diff --git a/packages/airnode-admin/src/sdk.ts b/packages/airnode-admin/src/sdk.ts index 181990318c..1874ff3e12 100644 --- a/packages/airnode-admin/src/sdk.ts +++ b/packages/airnode-admin/src/sdk.ts @@ -14,7 +14,10 @@ export class AdminSdk { admin.deriveWalletPathFromSponsorAddress(sponsorAddress); static useAirnodeRrp = evm.useAirnodeRrp; - constructor(public airnodeRrp: AirnodeRrpV0, public requesterAuthorizerWithAirnode: RequesterAuthorizerWithAirnode) {} + constructor( + public airnodeRrp: AirnodeRrpV0, + public requesterAuthorizerWithAirnode: RequesterAuthorizerWithAirnode + ) {} deriveAirnodeXpub = (airnodeMnemonic: string) => admin.deriveAirnodeXpub(airnodeMnemonic); diff --git a/packages/airnode-deployer/CHANGELOG.md b/packages/airnode-deployer/CHANGELOG.md index 2293d3dde4..854780cc4d 100644 --- a/packages/airnode-deployer/CHANGELOG.md +++ b/packages/airnode-deployer/CHANGELOG.md @@ -1,5 +1,28 @@ # @api3/airnode-deployer +## 0.13.0 + +### Minor Changes + +- [#1888](https://github.com/api3dao/airnode/pull/1888) [`1da62631`](https://github.com/api3dao/airnode/commit/1da62631905cf4b49266f248c8c385b5106d4c4d) Thanks [@dcroote](https://github.com/dcroote)! - Bump OIS to v2.2.0 and make operationParameter optional within endpoint parameters + +### Patch Changes + +- [#1834](https://github.com/api3dao/airnode/pull/1834) [`a6efbe83`](https://github.com/api3dao/airnode/commit/a6efbe83d5f89f2fbdbf7e1a81f4e8adfcf1f68b) Thanks [@renovate](https://github.com/apps/renovate)! - Bump dev dependency @octokit/core to v5 + +- [#1830](https://github.com/api3dao/airnode/pull/1830) [`1d7e4b2f`](https://github.com/api3dao/airnode/commit/1d7e4b2fe4467cee05a6d5f4b34b772d377337df) Thanks [@renovate](https://github.com/apps/renovate)! - Update to @smithy package for aws-sdk + +- [#1893](https://github.com/api3dao/airnode/pull/1893) [`cefc5e4a`](https://github.com/api3dao/airnode/commit/cefc5e4abcc0f10a9b0b84b9bf55af2f34ffe1bd) Thanks [@dcroote](https://github.com/dcroote)! - Bump ois to v2.2.1 + +- [#1825](https://github.com/api3dao/airnode/pull/1825) [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3) Thanks [@renovate](https://github.com/apps/renovate)! - Apply prettier v3 formatting + +- Updated dependencies [[`502a5aa7`](https://github.com/api3dao/airnode/commit/502a5aa722eb4a1a6b921aa4a489916ffb04c22e), [`449fa396`](https://github.com/api3dao/airnode/commit/449fa39665025e1832d55a2e9cb8792b2b76de4f), [`87cee037`](https://github.com/api3dao/airnode/commit/87cee0372afc60acb141ad308d3664172f3cbdb6), [`1da62631`](https://github.com/api3dao/airnode/commit/1da62631905cf4b49266f248c8c385b5106d4c4d), [`d2e5a04b`](https://github.com/api3dao/airnode/commit/d2e5a04bf6e88de1888f044dfb171344171ba0ea), [`fb90c4c5`](https://github.com/api3dao/airnode/commit/fb90c4c5c207165a9b0c157af36da8ae1f3f84c5), [`1d7e4b2f`](https://github.com/api3dao/airnode/commit/1d7e4b2fe4467cee05a6d5f4b34b772d377337df), [`cefc5e4a`](https://github.com/api3dao/airnode/commit/cefc5e4abcc0f10a9b0b84b9bf55af2f34ffe1bd), [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3)]: + - @api3/airnode-node@0.13.0 + - @api3/airnode-protocol@0.13.0 + - @api3/airnode-validator@0.13.0 + - @api3/airnode-utilities@0.13.0 + - @api3/airnode-abi@0.13.0 + ## 0.12.0 ### Patch Changes diff --git a/packages/airnode-deployer/config/config.example.json b/packages/airnode-deployer/config/config.example.json index 0da2e8c1f9..224e79a40b 100644 --- a/packages/airnode-deployer/config/config.example.json +++ b/packages/airnode-deployer/config/config.example.json @@ -59,7 +59,7 @@ }, "logFormat": "plain", "logLevel": "INFO", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "cloudProvider": { "type": "aws", "region": "us-east-1", @@ -94,7 +94,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-deployer/package.json b/packages/airnode-deployer/package.json index ba2b5e6651..61e1bcdb8f 100644 --- a/packages/airnode-deployer/package.json +++ b/packages/airnode-deployer/package.json @@ -1,7 +1,7 @@ { "name": "@api3/airnode-deployer", "license": "MIT", - "version": "0.12.0", + "version": "0.13.0", "private": false, "bin": { "airnode-deployer": "./dist/bin/deployer.js" @@ -23,19 +23,19 @@ "webpack:dev": "webpack --mode development" }, "dependencies": { - "@api3/airnode-abi": "^0.12.0", - "@api3/airnode-node": "^0.12.0", - "@api3/airnode-protocol": "^0.12.0", - "@api3/airnode-utilities": "^0.12.0", - "@api3/airnode-validator": "^0.12.0", + "@api3/airnode-abi": "^0.13.0", + "@api3/airnode-node": "^0.13.0", + "@api3/airnode-protocol": "^0.13.0", + "@api3/airnode-utilities": "^0.13.0", + "@api3/airnode-validator": "^0.13.0", "@api3/promise-utils": "^0.4.0", - "@aws-sdk/client-s3": "^3.383.0", - "@aws-sdk/signature-v4-crt": "^3.378.0", - "@google-cloud/storage": "^7.0.1", + "@aws-sdk/client-s3": "^3.418.0", + "@aws-sdk/signature-v4-crt": "^3.418.0", + "@google-cloud/storage": "^7.1.0", "adm-zip": "^0.5.10", "chalk": "^4.1.2", "cli-table3": "^0.6.3", - "compare-versions": "^6.0.0", + "compare-versions": "^6.1.0", "date-fns": "^2.30.0", "date-fns-tz": "^2.0.0", "dotenv": "^16.3.1", @@ -43,26 +43,26 @@ "lodash": "^4.17.21", "ora": "^5.4.1", "yargs": "^17.7.2", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { - "@aws-sdk/util-stream-node": "^3.360.0", + "@aws-sdk/util-stream-node": "^3.370.0", "@google-cloud/functions-framework": "^3.3.0", - "@types/adm-zip": "^0.5.0", - "@types/aws-lambda": "^8.10.119", - "@types/lodash": "^4.14.195", - "@types/node": "^18.16.19", - "@types/yargs": "^17.0.24", + "@types/adm-zip": "^0.5.3", + "@types/aws-lambda": "^8.10.125", + "@types/lodash": "^4.14.200", + "@types/node": "^18.18.7", + "@types/yargs": "^17.0.29", "aws-sdk-client-mock": "^3.0.0", "aws-sdk-client-mock-jest": "^3.0.0", "copyfiles": "^2.4.1", - "esbuild-loader": "^3.0.1", - "jest": "^29.6.0", - "rimraf": "^5.0.1", + "esbuild-loader": "^4.0.2", + "jest": "^29.7.0", + "rimraf": "^5.0.5", "ts-jest": "^29.1.1", "ts-node": "^10.9.1", - "typescript": "^5.1.6", - "webpack": "^5.88.1", + "typescript": "^5.2.2", + "webpack": "^5.89.0", "webpack-cli": "^5.1.4", "webpack-ignore-dynamic-require": "^1.0.0" } diff --git a/packages/airnode-deployer/src/cli/commands.test.ts b/packages/airnode-deployer/src/cli/commands.test.ts index 45bfbbc55f..36cab28838 100644 --- a/packages/airnode-deployer/src/cli/commands.test.ts +++ b/packages/airnode-deployer/src/cli/commands.test.ts @@ -71,7 +71,7 @@ describe('deployer commands', () => { jest .spyOn(logger, 'getSpinner') .mockImplementation( - () => ({ start: () => mockSpinner, succeed: () => mockSpinner } as unknown as logger.Spinner) + () => ({ start: () => mockSpinner, succeed: () => mockSpinner }) as unknown as logger.Spinner ); jest.spyOn(logger, 'inDebugMode').mockImplementation(() => false); tempConfigDir = fs.mkdtempSync(path.join(os.tmpdir(), 'airnode-rollback-test')); diff --git a/packages/airnode-deployer/terraform/aws/main.tf b/packages/airnode-deployer/terraform/aws/main.tf index 4dbc724226..54a03384a6 100644 --- a/packages/airnode-deployer/terraform/aws/main.tf +++ b/packages/airnode-deployer/terraform/aws/main.tf @@ -300,7 +300,7 @@ module "signOevReq" { name = "${local.name_prefix}-signOevReq" handler = "index.signOevReq" source_dir = var.handler_dir - memory_size = 256 + memory_size = 2048 timeout = 30 configuration_file = var.configuration_file secrets_file = var.secrets_file diff --git a/packages/airnode-deployer/terraform/aws/templates/oevGw.yaml.tpl b/packages/airnode-deployer/terraform/aws/templates/oevGw.yaml.tpl index 783205d9fa..a76e6adbb2 100644 --- a/packages/airnode-deployer/terraform/aws/templates/oevGw.yaml.tpl +++ b/packages/airnode-deployer/terraform/aws/templates/oevGw.yaml.tpl @@ -18,7 +18,7 @@ components: type: object required: - chainId - - dapiServerAddress + - api3ServerV1 - oevProxyAddress - updateId - bidderAddress @@ -29,7 +29,7 @@ components: type: integer format: int32 minimum: 1 - dapiServerAddress: + api3ServerV1: type: string oevProxyAddress: type: string @@ -47,14 +47,11 @@ components: type: object required: - airnodeAddress - - endpointId - - encodedParameters + - templateId properties: airnodeAddress: type: string - endpointId: - type: string - encodedParameters: + templateId: type: string signedData: type: object @@ -82,7 +79,7 @@ components: value: | { "chainId": 1, - "dapiServerAddress": "0x...", + "api3ServerV1": "0x...", "oevProxyAddress": "0x...", "updateId": "0x...", "bidderAddress": "0x...", @@ -90,8 +87,7 @@ components: "beacons": [ { "airnodeAddress": "0x...", - "endpointId": "0x...", - "encodedParameters": "0x...", + "templateId": "0x...", "signedData": { "timestamp": "16...", "encodedValue": "0x...", @@ -100,8 +96,7 @@ components: }, { "airnodeAddress": "0x...", - "endpointId": "0x...", - "encodedParameters": "0x..." + "templateId": "0x...", } ] } diff --git a/packages/airnode-deployer/terraform/gcp/providers.tf b/packages/airnode-deployer/terraform/gcp/providers.tf index bf742a8c78..279254477e 100644 --- a/packages/airnode-deployer/terraform/gcp/providers.tf +++ b/packages/airnode-deployer/terraform/gcp/providers.tf @@ -2,7 +2,7 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = "~> 4.78" + version = "~> 4.84" } } diff --git a/packages/airnode-deployer/test/fixtures/config.aws.valid.json b/packages/airnode-deployer/test/fixtures/config.aws.valid.json index 92234f1d99..6776f44cb2 100644 --- a/packages/airnode-deployer/test/fixtures/config.aws.valid.json +++ b/packages/airnode-deployer/test/fixtures/config.aws.valid.json @@ -95,7 +95,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-deployer/test/fixtures/config.gcp.valid.json b/packages/airnode-deployer/test/fixtures/config.gcp.valid.json index fdf87554b8..06a24934fa 100644 --- a/packages/airnode-deployer/test/fixtures/config.gcp.valid.json +++ b/packages/airnode-deployer/test/fixtures/config.gcp.valid.json @@ -93,7 +93,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-examples/CHANGELOG.md b/packages/airnode-examples/CHANGELOG.md index 4100e31483..b375c69402 100644 --- a/packages/airnode-examples/CHANGELOG.md +++ b/packages/airnode-examples/CHANGELOG.md @@ -1,5 +1,27 @@ # @api3/airnode-examples +## 0.13.0 + +### Minor Changes + +- [#1888](https://github.com/api3dao/airnode/pull/1888) [`1da62631`](https://github.com/api3dao/airnode/commit/1da62631905cf4b49266f248c8c385b5106d4c4d) Thanks [@dcroote](https://github.com/dcroote)! - Bump OIS to v2.2.0 and make operationParameter optional within endpoint parameters + +### Patch Changes + +- [#1895](https://github.com/api3dao/airnode/pull/1895) [`79462275`](https://github.com/api3dao/airnode/commit/7946227592ff28b3b2e3bddd71c157988402cd2e) Thanks [@dcroote](https://github.com/dcroote)! - Check for AirnodeRrp deployment in localhost flow + +- [#1869](https://github.com/api3dao/airnode/pull/1869) [`fb90c4c5`](https://github.com/api3dao/airnode/commit/fb90c4c5c207165a9b0c157af36da8ae1f3f84c5) Thanks [@dcroote](https://github.com/dcroote)! - Test HTTP gateways in E2E integration test + +- [#1825](https://github.com/api3dao/airnode/pull/1825) [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3) Thanks [@renovate](https://github.com/apps/renovate)! - Apply prettier v3 formatting + +- Updated dependencies [[`a6efbe83`](https://github.com/api3dao/airnode/commit/a6efbe83d5f89f2fbdbf7e1a81f4e8adfcf1f68b), [`502a5aa7`](https://github.com/api3dao/airnode/commit/502a5aa722eb4a1a6b921aa4a489916ffb04c22e), [`449fa396`](https://github.com/api3dao/airnode/commit/449fa39665025e1832d55a2e9cb8792b2b76de4f), [`87cee037`](https://github.com/api3dao/airnode/commit/87cee0372afc60acb141ad308d3664172f3cbdb6), [`1da62631`](https://github.com/api3dao/airnode/commit/1da62631905cf4b49266f248c8c385b5106d4c4d), [`d2e5a04b`](https://github.com/api3dao/airnode/commit/d2e5a04bf6e88de1888f044dfb171344171ba0ea), [`fb90c4c5`](https://github.com/api3dao/airnode/commit/fb90c4c5c207165a9b0c157af36da8ae1f3f84c5), [`1d7e4b2f`](https://github.com/api3dao/airnode/commit/1d7e4b2fe4467cee05a6d5f4b34b772d377337df), [`cefc5e4a`](https://github.com/api3dao/airnode/commit/cefc5e4abcc0f10a9b0b84b9bf55af2f34ffe1bd), [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3)]: + - @api3/airnode-deployer@0.13.0 + - @api3/airnode-node@0.13.0 + - @api3/airnode-protocol@0.13.0 + - @api3/airnode-utilities@0.13.0 + - @api3/airnode-admin@0.13.0 + - @api3/airnode-abi@0.13.0 + ## 0.12.0 ### Minor Changes diff --git a/packages/airnode-examples/integrations/authenticated-coinmarketcap/config.example.json b/packages/airnode-examples/integrations/authenticated-coinmarketcap/config.example.json index 0df12ad642..47be0bcea4 100644 --- a/packages/airnode-examples/integrations/authenticated-coinmarketcap/config.example.json +++ b/packages/airnode-examples/integrations/authenticated-coinmarketcap/config.example.json @@ -65,7 +65,7 @@ }, "logFormat": "plain", "logLevel": "DEBUG", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -83,7 +83,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinMarketCap Basic Authenticated Request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-examples/integrations/authenticated-coinmarketcap/create-config.ts b/packages/airnode-examples/integrations/authenticated-coinmarketcap/create-config.ts index d315efc76f..a4278bf557 100644 --- a/packages/airnode-examples/integrations/authenticated-coinmarketcap/create-config.ts +++ b/packages/airnode-examples/integrations/authenticated-coinmarketcap/create-config.ts @@ -90,7 +90,7 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ templates: [], ois: [ { - oisFormat: '2.1.0', + oisFormat: '2.3.1', title: 'CoinMarketCap Basic Authenticated Request', version: '1.0.0', apiSpecifications: { diff --git a/packages/airnode-examples/integrations/coingecko-cross-chain-authorizer/config.example.json b/packages/airnode-examples/integrations/coingecko-cross-chain-authorizer/config.example.json index beb57f2721..da27a54c0f 100644 --- a/packages/airnode-examples/integrations/coingecko-cross-chain-authorizer/config.example.json +++ b/packages/airnode-examples/integrations/coingecko-cross-chain-authorizer/config.example.json @@ -67,17 +67,21 @@ "enabled": false }, "httpGateway": { - "enabled": false + "enabled": true, + "maxConcurrency": 20, + "corsOrigins": [] }, "httpSignedDataGateway": { - "enabled": false + "enabled": true, + "maxConcurrency": 20, + "corsOrigins": [] }, "oevGateway": { "enabled": false }, "logFormat": "plain", "logLevel": "DEBUG", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -89,13 +93,25 @@ "cacheResponses": false } ], - "http": [], - "httpSignedData": [] + "http": [ + { + "endpointId": "0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4", + "oisTitle": "CoinGecko basic request", + "endpointName": "coinMarketData" + } + ], + "httpSignedData": [ + { + "endpointId": "0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4", + "oisTitle": "CoinGecko basic request", + "endpointName": "coinMarketData" + } + ] }, "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-examples/integrations/coingecko-cross-chain-authorizer/create-config.ts b/packages/airnode-examples/integrations/coingecko-cross-chain-authorizer/create-config.ts index d54f83eee4..5085c263af 100644 --- a/packages/airnode-examples/integrations/coingecko-cross-chain-authorizer/create-config.ts +++ b/packages/airnode-examples/integrations/coingecko-cross-chain-authorizer/create-config.ts @@ -75,10 +75,14 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ enabled: false, }, httpGateway: { - enabled: false, + enabled: true, + maxConcurrency: 20, + corsOrigins: [], }, httpSignedDataGateway: { - enabled: false, + enabled: true, + maxConcurrency: 20, + corsOrigins: [], }, oevGateway: { enabled: false, @@ -97,13 +101,25 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ cacheResponses: false, }, ], - http: [], - httpSignedData: [], + http: [ + { + endpointId: '0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4', + oisTitle: 'CoinGecko basic request', + endpointName: 'coinMarketData', + }, + ], + httpSignedData: [ + { + endpointId: '0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4', + oisTitle: 'CoinGecko basic request', + endpointName: 'coinMarketData', + }, + ], }, templates: [], ois: [ { - oisFormat: '2.1.0', + oisFormat: '2.3.1', title: 'CoinGecko basic request', version: '1.0.0', apiSpecifications: { diff --git a/packages/airnode-examples/integrations/coingecko-http-gateways/config.example.json b/packages/airnode-examples/integrations/coingecko-http-gateways/config.example.json index 8af20aac2e..8e0a8cef9f 100644 --- a/packages/airnode-examples/integrations/coingecko-http-gateways/config.example.json +++ b/packages/airnode-examples/integrations/coingecko-http-gateways/config.example.json @@ -69,7 +69,7 @@ }, "logFormat": "plain", "logLevel": "DEBUG", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -99,7 +99,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-examples/integrations/coingecko-http-gateways/create-config.ts b/packages/airnode-examples/integrations/coingecko-http-gateways/create-config.ts index 9325ec4f09..f3aebc3567 100644 --- a/packages/airnode-examples/integrations/coingecko-http-gateways/create-config.ts +++ b/packages/airnode-examples/integrations/coingecko-http-gateways/create-config.ts @@ -106,7 +106,7 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ templates: [], ois: [ { - oisFormat: '2.1.0', + oisFormat: '2.3.1', title: 'CoinGecko basic request', version: '1.0.0', apiSpecifications: { diff --git a/packages/airnode-examples/integrations/coingecko-post-processing/config.example.json b/packages/airnode-examples/integrations/coingecko-post-processing/config.example.json index c84ee85512..fb3885e63c 100644 --- a/packages/airnode-examples/integrations/coingecko-post-processing/config.example.json +++ b/packages/airnode-examples/integrations/coingecko-post-processing/config.example.json @@ -65,7 +65,7 @@ }, "logFormat": "plain", "logLevel": "DEBUG", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -83,7 +83,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko coins markets request", "version": "1.0.0", "apiSpecifications": { @@ -196,13 +196,11 @@ } } ], - "postProcessingSpecifications": [ - { - "environment": "Node", - "timeoutMs": 5000, - "value": "\n // Log out every coin data\n input.forEach((coinData) => {\n console.log(`[Post-processing snippet]: Received the following coin data: \\${JSON.stringify(coinData, null, 2)}`)\n })\n\n const sum = (nums) => nums.reduce((acc, num) => acc + num, 0);\n const average = sum(input.map((coinData) => coinData.current_price)) / input.length;\n const percentageChange = sum(input.map((coinData) => coinData.price_change_percentage_30d_in_currency)) / input.length;\n\n // Create the data to be sent on chain and multiply it by 10^8 to preserve precision\n const output = [average, percentageChange].map((x) => x * 10 ** 8);\n " - } - ] + "postProcessingSpecificationV2": { + "environment": "Node", + "timeoutMs": 5000, + "value": "async function({ response }) {\n // Log out every coin data\n response.forEach((coinData) => {\n console.log(`[Post-processing snippet]: Received the following coin data: \\${JSON.stringify(coinData, null, 2)}`);\n });\n\n const sum = (nums) => nums.reduce((acc, num) => acc + num, 0);\n const average = sum(response.map((coinData) => coinData.current_price)) / response.length;\n const percentageChange =\n sum(response.map((coinData) => coinData.price_change_percentage_30d_in_currency)) / response.length;\n\n // Create the data to be sent on chain and multiply it by 10^8 to preserve precision\n return { response: [average, percentageChange].map((x) => x * 10 ** 8) };\n}" + } } ] } diff --git a/packages/airnode-examples/integrations/coingecko-post-processing/create-config.ts b/packages/airnode-examples/integrations/coingecko-post-processing/create-config.ts index 202c987b6c..852d60bb2b 100644 --- a/packages/airnode-examples/integrations/coingecko-post-processing/create-config.ts +++ b/packages/airnode-examples/integrations/coingecko-post-processing/create-config.ts @@ -90,7 +90,7 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ templates: [], ois: [ { - oisFormat: '2.1.0', + oisFormat: '2.3.1', title: 'CoinGecko coins markets request', version: '1.0.0', apiSpecifications: { @@ -203,25 +203,26 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ }, }, ], - postProcessingSpecifications: [ - { - environment: 'Node', - timeoutMs: 5000, - value: ` - // Log out every coin data - input.forEach((coinData) => { - console.log(\`[Post-processing snippet]: Received the following coin data: \\\${JSON.stringify(coinData, null, 2)}\`) - }) + postProcessingSpecificationV2: { + environment: 'Node', + timeoutMs: 5000, + value: ` +async function({ response }) { + // Log out every coin data + response.forEach((coinData) => { + console.log(\`[Post-processing snippet]: Received the following coin data: \\\${JSON.stringify(coinData, null, 2)}\`); + }); - const sum = (nums) => nums.reduce((acc, num) => acc + num, 0); - const average = sum(input.map((coinData) => coinData.current_price)) / input.length; - const percentageChange = sum(input.map((coinData) => coinData.price_change_percentage_30d_in_currency)) / input.length; + const sum = (nums) => nums.reduce((acc, num) => acc + num, 0); + const average = sum(response.map((coinData) => coinData.current_price)) / response.length; + const percentageChange = + sum(response.map((coinData) => coinData.price_change_percentage_30d_in_currency)) / response.length; - // Create the data to be sent on chain and multiply it by 10^8 to preserve precision - const output = [average, percentageChange].map((x) => x * 10 ** 8); - `, - }, - ], + // Create the data to be sent on chain and multiply it by 10^8 to preserve precision + return { response: [average, percentageChange].map((x) => x * 10 ** 8) }; +} + `.trim(), + }, }, ], }, diff --git a/packages/airnode-examples/integrations/coingecko-pre-processing/config.example.json b/packages/airnode-examples/integrations/coingecko-pre-processing/config.example.json index c0cb6fa806..867cf23eac 100644 --- a/packages/airnode-examples/integrations/coingecko-pre-processing/config.example.json +++ b/packages/airnode-examples/integrations/coingecko-pre-processing/config.example.json @@ -65,7 +65,7 @@ }, "logFormat": "plain", "logLevel": "DEBUG", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -83,7 +83,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko history data request", "version": "1.0.0", "apiSpecifications": { @@ -163,13 +163,11 @@ } } ], - "preProcessingSpecifications": [ - { - "environment": "Node", - "timeoutMs": 5000, - "value": "\n const rawDate = new Date(input.unixTimestamp * 1000);\n const day = rawDate.getDate().toString().padStart(2, '0');\n const month = (rawDate.getMonth() + 1).toString().padStart(2, '0'); // Months start at 0\n const year = rawDate.getFullYear();\n\n const formattedDate = day + '-' + month + '-' + year;\n const output = {...input, unixTimestamp: formattedDate};\n\n console.log(`[Pre-processing snippet]: Formatted \\${input.unixTimestamp} to \\${formattedDate}.`)\n " - } - ] + "preProcessingSpecificationV2": { + "environment": "Node", + "timeoutMs": 5000, + "value": "async ({endpointParameters}) => {\n const rawDate = new Date(endpointParameters.unixTimestamp * 1000);\n const day = rawDate.getDate().toString().padStart(2, '0');\n const month = (rawDate.getMonth() + 1).toString().padStart(2, '0'); // Months start at 0\n const year = rawDate.getFullYear();\n\n const formattedDate = day + '-' + month + '-' + year;\n const newEndpointParameters = {...endpointParameters, unixTimestamp: formattedDate};\n\n console.log(`[Pre-processing snippet]: Formatted \\${endpointParameters.unixTimestamp} to \\${formattedDate}.`)\n return {endpointParameters: newEndpointParameters};\n}" + } } ] } diff --git a/packages/airnode-examples/integrations/coingecko-pre-processing/create-config.ts b/packages/airnode-examples/integrations/coingecko-pre-processing/create-config.ts index 304a3065cc..7317dc7f54 100644 --- a/packages/airnode-examples/integrations/coingecko-pre-processing/create-config.ts +++ b/packages/airnode-examples/integrations/coingecko-pre-processing/create-config.ts @@ -90,7 +90,7 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ templates: [], ois: [ { - oisFormat: '2.1.0', + oisFormat: '2.3.1', title: 'CoinGecko history data request', version: '1.0.0', apiSpecifications: { @@ -170,23 +170,24 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ }, }, ], - preProcessingSpecifications: [ - { - environment: 'Node', - timeoutMs: 5000, - value: ` - const rawDate = new Date(input.unixTimestamp * 1000); - const day = rawDate.getDate().toString().padStart(2, '0'); - const month = (rawDate.getMonth() + 1).toString().padStart(2, '0'); // Months start at 0 - const year = rawDate.getFullYear(); + preProcessingSpecificationV2: { + environment: 'Node', + timeoutMs: 5000, + value: ` +async ({endpointParameters}) => { + const rawDate = new Date(endpointParameters.unixTimestamp * 1000); + const day = rawDate.getDate().toString().padStart(2, '0'); + const month = (rawDate.getMonth() + 1).toString().padStart(2, '0'); // Months start at 0 + const year = rawDate.getFullYear(); - const formattedDate = day + '-' + month + '-' + year; - const output = {...input, unixTimestamp: formattedDate}; + const formattedDate = day + '-' + month + '-' + year; + const newEndpointParameters = {...endpointParameters, unixTimestamp: formattedDate}; - console.log(\`[Pre-processing snippet]: Formatted \\\${input.unixTimestamp} to \\\${formattedDate}.\`) - `, - }, - ], + console.log(\`[Pre-processing snippet]: Formatted \\\${endpointParameters.unixTimestamp} to \\\${formattedDate}.\`) + return {endpointParameters: newEndpointParameters}; +} + `.trim(), + }, }, ], }, diff --git a/packages/airnode-examples/integrations/coingecko-template/config.example.json b/packages/airnode-examples/integrations/coingecko-template/config.example.json index 166593b129..ee6e67cb7f 100644 --- a/packages/airnode-examples/integrations/coingecko-template/config.example.json +++ b/packages/airnode-examples/integrations/coingecko-template/config.example.json @@ -65,7 +65,7 @@ }, "logFormat": "plain", "logLevel": "DEBUG", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -89,7 +89,7 @@ ], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-examples/integrations/coingecko-template/create-config.ts b/packages/airnode-examples/integrations/coingecko-template/create-config.ts index 48c292b22f..a941f0ce03 100644 --- a/packages/airnode-examples/integrations/coingecko-template/create-config.ts +++ b/packages/airnode-examples/integrations/coingecko-template/create-config.ts @@ -98,7 +98,7 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ ], ois: [ { - oisFormat: '2.1.0', + oisFormat: '2.3.1', title: 'CoinGecko basic request', version: '1.0.0', apiSpecifications: { diff --git a/packages/airnode-examples/integrations/coingecko/config.example.json b/packages/airnode-examples/integrations/coingecko/config.example.json index 9cfb7ed345..b528355295 100644 --- a/packages/airnode-examples/integrations/coingecko/config.example.json +++ b/packages/airnode-examples/integrations/coingecko/config.example.json @@ -65,7 +65,7 @@ }, "logFormat": "plain", "logLevel": "DEBUG", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -83,7 +83,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-examples/integrations/coingecko/create-config.ts b/packages/airnode-examples/integrations/coingecko/create-config.ts index e16cb19d02..8bb1117203 100644 --- a/packages/airnode-examples/integrations/coingecko/create-config.ts +++ b/packages/airnode-examples/integrations/coingecko/create-config.ts @@ -90,7 +90,7 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ templates: [], ois: [ { - oisFormat: '2.1.0', + oisFormat: '2.3.1', title: 'CoinGecko basic request', version: '1.0.0', apiSpecifications: { diff --git a/packages/airnode-examples/integrations/config-utils.ts b/packages/airnode-examples/integrations/config-utils.ts index 57872da327..022a46377a 100644 --- a/packages/airnode-examples/integrations/config-utils.ts +++ b/packages/airnode-examples/integrations/config-utils.ts @@ -91,8 +91,8 @@ export const addAirnodeRrpV0DryRunAddress = async (config: Config) => { export const generateConfigFile = async (dirname: string, config: Config, generateExampleFile: boolean) => { const filename = generateExampleFile ? 'config.example.json' : 'config.json'; - const updatedConfig = await addAirnodeRrpV0DryRunAddress(config); - const formattedConfig = format(JSON.stringify(updatedConfig, null, 2), { parser: 'json', printWidth: 120 }); + const updatedConfig = generateExampleFile ? config : await addAirnodeRrpV0DryRunAddress(config); + const formattedConfig = await format(JSON.stringify(updatedConfig, null, 2), { parser: 'json', printWidth: 120 }); writeFileSync(join(dirname, filename), formattedConfig); cliPrint.info(`A '${filename}' has been created.`); diff --git a/packages/airnode-examples/integrations/failing-example/config.example.json b/packages/airnode-examples/integrations/failing-example/config.example.json index e35a701355..02569a5f16 100644 --- a/packages/airnode-examples/integrations/failing-example/config.example.json +++ b/packages/airnode-examples/integrations/failing-example/config.example.json @@ -65,7 +65,7 @@ }, "logFormat": "plain", "logLevel": "DEBUG", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -83,7 +83,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "Failure Example", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-examples/integrations/failing-example/create-config.ts b/packages/airnode-examples/integrations/failing-example/create-config.ts index de8e8fd3be..cf103fb426 100644 --- a/packages/airnode-examples/integrations/failing-example/create-config.ts +++ b/packages/airnode-examples/integrations/failing-example/create-config.ts @@ -90,7 +90,7 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ templates: [], ois: [ { - oisFormat: '2.1.0', + oisFormat: '2.3.1', title: 'Failure Example', version: '1.0.0', apiSpecifications: { diff --git a/packages/airnode-examples/integrations/relay-security-schemes/config.example.json b/packages/airnode-examples/integrations/relay-security-schemes/config.example.json index 3fa17f04e8..83f6d98275 100644 --- a/packages/airnode-examples/integrations/relay-security-schemes/config.example.json +++ b/packages/airnode-examples/integrations/relay-security-schemes/config.example.json @@ -65,7 +65,7 @@ }, "logFormat": "plain", "logLevel": "DEBUG", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -83,7 +83,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "Relay Security Schemes via httpbin", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-examples/integrations/relay-security-schemes/create-config.ts b/packages/airnode-examples/integrations/relay-security-schemes/create-config.ts index 2829b34c71..e2421abd02 100644 --- a/packages/airnode-examples/integrations/relay-security-schemes/create-config.ts +++ b/packages/airnode-examples/integrations/relay-security-schemes/create-config.ts @@ -90,7 +90,7 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ templates: [], ois: [ { - oisFormat: '2.1.0', + oisFormat: '2.3.1', title: 'Relay Security Schemes via httpbin', version: '1.0.0', apiSpecifications: { diff --git a/packages/airnode-examples/integrations/weather-multi-value/config.example.json b/packages/airnode-examples/integrations/weather-multi-value/config.example.json index 86c75fb43e..6d55f0b901 100644 --- a/packages/airnode-examples/integrations/weather-multi-value/config.example.json +++ b/packages/airnode-examples/integrations/weather-multi-value/config.example.json @@ -65,7 +65,7 @@ }, "logFormat": "plain", "logLevel": "DEBUG", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -83,7 +83,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "OpenWeather Multiple Encoded Values", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-examples/integrations/weather-multi-value/create-config.ts b/packages/airnode-examples/integrations/weather-multi-value/create-config.ts index bbcc518bc1..bc57f36e69 100644 --- a/packages/airnode-examples/integrations/weather-multi-value/create-config.ts +++ b/packages/airnode-examples/integrations/weather-multi-value/create-config.ts @@ -90,7 +90,7 @@ const createConfig = async (generateExampleFile: boolean): Promise => ({ templates: [], ois: [ { - oisFormat: '2.1.0', + oisFormat: '2.3.1', title: 'OpenWeather Multiple Encoded Values', version: '1.0.0', apiSpecifications: { diff --git a/packages/airnode-examples/package.json b/packages/airnode-examples/package.json index 855b5e84fb..c6b7001ba8 100644 --- a/packages/airnode-examples/package.json +++ b/packages/airnode-examples/package.json @@ -1,7 +1,7 @@ { "name": "@api3/airnode-examples", "license": "MIT", - "version": "0.12.0", + "version": "0.13.0", "private": false, "description": "A collection of examples showcasing the features of Airnode", "files": [ @@ -29,33 +29,33 @@ "run-airnode-locally": "ts-node src/scripts/run-airnode-locally.ts", "sponsor-requester": "ts-node src/scripts/sponsor-requester.ts", "stop-local-airnode": "ts-node src/scripts/stop-local-airnode.ts", - "test": "jest --selectProjects unit", + "test": "NODE_OPTIONS=--experimental-vm-modules jest --selectProjects unit", "test:e2e": "jest --selectProjects e2e" }, "dependencies": { - "@api3/airnode-abi": "^0.12.0", - "@api3/airnode-admin": "^0.12.0", - "@api3/airnode-deployer": "^0.12.0", - "@api3/airnode-node": "^0.12.0", - "@api3/airnode-protocol": "^0.12.0", - "@api3/airnode-utilities": "^0.12.0", + "@api3/airnode-abi": "^0.13.0", + "@api3/airnode-admin": "^0.13.0", + "@api3/airnode-deployer": "^0.13.0", + "@api3/airnode-node": "^0.13.0", + "@api3/airnode-protocol": "^0.13.0", + "@api3/airnode-utilities": "^0.13.0", "ethers": "^5.7.2", "is-wsl": "^2.2.0" }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-waffle": "^2.0.6", - "@types/jest": "^29.5.2", - "@types/node": "^18.16.19", - "@types/prompts": "^2.4.4", + "@types/jest": "^29.5.6", + "@types/node": "^18.18.7", + "@types/prompts": "^2.4.7", "chalk": "^4.1.2", "dotenv": "^16.3.1", "ethereum-waffle": "^4.0.10", "hardhat": "^2.14.1", - "jest": "^29.6.0", + "jest": "^29.7.0", "prompts": "^2.4.2", "ts-jest": "^29.1.1", "ts-node": "^10.9.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } } diff --git a/packages/airnode-examples/src/scripts/create-airnode-config.ts b/packages/airnode-examples/src/scripts/create-airnode-config.ts index 96c5f56a32..daf599448c 100644 --- a/packages/airnode-examples/src/scripts/create-airnode-config.ts +++ b/packages/airnode-examples/src/scripts/create-airnode-config.ts @@ -1,7 +1,24 @@ -import { readIntegrationInfo, runAndHandleErrors } from '../'; +import { readIntegrationInfo, runAndHandleErrors, getDeployedContract, cliPrint } from '../'; const main = async () => { const integrationInfo = readIntegrationInfo(); + + // If using the localhost network, check that AirnodeRrp was deployed + if (integrationInfo.network === 'localhost') { + try { + await getDeployedContract('@api3/airnode-protocol/contracts/rrp/AirnodeRrpV0.sol'); + } catch (e) { + if (e instanceof Error && (e.message.includes('ENOENT') || e.message.includes('invalid contract address'))) { + cliPrint.error( + 'AirnodeRrpV0 contract deployment not found. Please follow the RRP deployment ' + + 'instructions in the README before running this command.' + ); + process.exit(1); + } + throw e; + } + } + // Import the "create-config" file from the chosen integration. See the respective "create-config.ts" file for // details. const createConfig = await import(`../../integrations/${integrationInfo.integration}/create-config.ts`); diff --git a/packages/airnode-examples/src/utils.ts b/packages/airnode-examples/src/utils.ts index 88403b150d..955b420903 100644 --- a/packages/airnode-examples/src/utils.ts +++ b/packages/airnode-examples/src/utils.ts @@ -3,7 +3,8 @@ import { join } from 'path'; import { parse as parseEnvFile } from 'dotenv'; import prompts, { PromptObject } from 'prompts'; import isWsl from 'is-wsl'; -import references from '@api3/airnode-protocol/deployments/references.json'; +import { AirnodeRrpV0 } from '@api3/airnode-protocol/deployments/references.json'; +import { hardhatConfig } from '@api3/chains'; export const supportedNetworks = ['ethereum-sepolia-testnet', 'polygon-testnet', 'ethereum-goerli-testnet'] as const; @@ -104,12 +105,9 @@ export const setMaxPromiseTimeout = (promise: Promise, timeoutMs: number): * @returns The AirnodeRrpV0 contract address for the named network */ export const getExistingAirnodeRrpV0 = (networkName: string) => { - const { chainNames, AirnodeRrpV0 } = references; + const networks = hardhatConfig.networks(); - // get network ID (key) for a given network name (value) - const networkId = (Object.keys(chainNames) as (keyof typeof chainNames)[]).find((name) => { - return chainNames[name] === networkName; - }); + const networkId = networks[networkName].chainId.toString() as keyof typeof AirnodeRrpV0; if (networkId) { return AirnodeRrpV0[networkId]; diff --git a/packages/airnode-examples/test/e2e/coingecko-local.feature.ts b/packages/airnode-examples/test/e2e/coingecko-local.feature.ts index 4c36665c8c..273c25fdad 100644 --- a/packages/airnode-examples/test/e2e/coingecko-local.feature.ts +++ b/packages/airnode-examples/test/e2e/coingecko-local.feature.ts @@ -1,6 +1,7 @@ import { readFileSync, writeFileSync } from 'fs'; import { join } from 'path'; -import { Config } from '@api3/airnode-node'; +import { ethers } from 'ethers'; +import { Config, DEFAULT_PATH_KEY } from '@api3/airnode-node'; import { logger } from '@api3/airnode-utilities'; import { runCommand, runCommandInBackground } from '../utils'; @@ -31,6 +32,7 @@ const removeFulfillmentGasLimit = () => { const config: Config = JSON.parse(readFileSync(configPath, 'utf8')); delete config.chains[0].options.fulfillmentGasLimit; writeFileSync(configPath, JSON.stringify(config, null, 2)); + return config; }; describe('Coingecko integration with containerized Airnode and hardhat', () => { @@ -41,7 +43,7 @@ describe('Coingecko integration with containerized Airnode and hardhat', () => { runCommand('yarn deploy-rrp-dry-run'); runCommand('yarn create-airnode-config'); runCommand('yarn create-airnode-secrets'); - removeFulfillmentGasLimit(); + const config = removeFulfillmentGasLimit(); runCommand(`yarn ts-node integrations/${integration}/deploy-authorizers-and-update-config`); runCommandInBackground('yarn run-airnode-locally'); @@ -55,15 +57,39 @@ describe('Coingecko integration with containerized Airnode and hardhat', () => { const pathOfResponseText = 'Ethereum price is'; expect(response).toContain(pathOfResponseText); - const priceText = response.split(pathOfResponseText)[1]; expect(priceText).toContain('USD'); + const priceStr = priceText.split('USD')[0].trim(); + const price = Number(priceStr); + logger.log(`Blockchain request: The Ethereum price is ${price} USD.`); + + const endpointId = config.triggers.rrp[0].endpointId; + const timesReservedParameter = config.ois[0].endpoints[0].reservedParameters.find((rp) => rp.name === '_times'); + const timesValue = Number(timesReservedParameter!.fixed); + + const httpResponse = runCommand( + `curl --silent --show-error -X POST -H 'Content-Type: application/json' -d '{"parameters": {"coinId": "ethereum"}}' 'http://localhost:3000/http-data/${DEFAULT_PATH_KEY}/${endpointId}'` + ); + const httpGatewayPrice = Number(JSON.parse(httpResponse).values[0]) / timesValue; + expect(httpGatewayPrice).toEqual(expect.any(Number)); + logger.log(`HTTP Gateway request: The Ethereum price is ${price} USD.`); + + const signedHttpResponse = runCommand( + `curl --silent --show-error -X POST -H 'Content-Type: application/json' -d '{"encodedParameters": "0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000657468657265756d000000000000000000000000000000000000000000000000"}' 'http://localhost:3000/http-signed-data/${DEFAULT_PATH_KEY}/${endpointId}'` + ); + const encodedValue = JSON.parse(signedHttpResponse).encodedValue; + const decodedBigNumber: ethers.BigNumber = ethers.utils.defaultAbiCoder.decode(['int256'], encodedValue)[0]; + const signedGatewayPrice = decodedBigNumber.toNumber() / timesValue; + expect(signedGatewayPrice).toEqual(expect.any(Number)); + logger.log(`Signed HTTP Gateway request: The Ethereum price is ${price} USD.`); - const price = priceText.split('USD')[0].trim(); - expect(Number(price)).toEqual(expect.any(Number)); - expect(Number(price).toString()).toBe(price); + // Values returned by all three requests should be similar + const allowedDifference = 50; // very conservative + expect(Math.abs(httpGatewayPrice - signedGatewayPrice)).toBeLessThan(allowedDifference); + expect(Math.abs(httpGatewayPrice - price)).toBeLessThan(allowedDifference); + expect(Math.abs(signedGatewayPrice - price)).toBeLessThan(allowedDifference); - logger.log(`The Ethereum price is ${price} USD.`); + logger.log('All three requests returned similar Ethereum price values.'); } finally { runCommand('yarn stop-local-airnode'); } diff --git a/packages/airnode-node/CHANGELOG.md b/packages/airnode-node/CHANGELOG.md index cdc3f8ba67..5ce2f41235 100644 --- a/packages/airnode-node/CHANGELOG.md +++ b/packages/airnode-node/CHANGELOG.md @@ -1,5 +1,32 @@ # @api3/airnode-node +## 0.13.0 + +### Minor Changes + +- [#1899](https://github.com/api3dao/airnode/pull/1899) [`449fa396`](https://github.com/api3dao/airnode/commit/449fa39665025e1832d55a2e9cb8792b2b76de4f) Thanks [@Siegrift](https://github.com/Siegrift)! - Import processing implementation from @api3/commons + +- [#1888](https://github.com/api3dao/airnode/pull/1888) [`1da62631`](https://github.com/api3dao/airnode/commit/1da62631905cf4b49266f248c8c385b5106d4c4d) Thanks [@dcroote](https://github.com/dcroote)! - Bump OIS to v2.2.0 and make operationParameter optional within endpoint parameters + +### Patch Changes + +- [#1859](https://github.com/api3dao/airnode/pull/1859) [`502a5aa7`](https://github.com/api3dao/airnode/commit/502a5aa722eb4a1a6b921aa4a489916ffb04c22e) Thanks [@dcroote](https://github.com/dcroote)! - Harmonize HTTP gateway response object when encoding fails compared to when it succeeds + +- [#1869](https://github.com/api3dao/airnode/pull/1869) [`fb90c4c5`](https://github.com/api3dao/airnode/commit/fb90c4c5c207165a9b0c157af36da8ae1f3f84c5) Thanks [@dcroote](https://github.com/dcroote)! - Test HTTP gateways in E2E integration test + +- [#1830](https://github.com/api3dao/airnode/pull/1830) [`1d7e4b2f`](https://github.com/api3dao/airnode/commit/1d7e4b2fe4467cee05a6d5f4b34b772d377337df) Thanks [@renovate](https://github.com/apps/renovate)! - Update to @smithy package for aws-sdk + +- [#1893](https://github.com/api3dao/airnode/pull/1893) [`cefc5e4a`](https://github.com/api3dao/airnode/commit/cefc5e4abcc0f10a9b0b84b9bf55af2f34ffe1bd) Thanks [@dcroote](https://github.com/dcroote)! - Bump ois to v2.2.1 + +- [#1825](https://github.com/api3dao/airnode/pull/1825) [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3) Thanks [@renovate](https://github.com/apps/renovate)! - Apply prettier v3 formatting + +- Updated dependencies [[`87cee037`](https://github.com/api3dao/airnode/commit/87cee0372afc60acb141ad308d3664172f3cbdb6), [`1da62631`](https://github.com/api3dao/airnode/commit/1da62631905cf4b49266f248c8c385b5106d4c4d), [`d2e5a04b`](https://github.com/api3dao/airnode/commit/d2e5a04bf6e88de1888f044dfb171344171ba0ea), [`1d7e4b2f`](https://github.com/api3dao/airnode/commit/1d7e4b2fe4467cee05a6d5f4b34b772d377337df), [`cefc5e4a`](https://github.com/api3dao/airnode/commit/cefc5e4abcc0f10a9b0b84b9bf55af2f34ffe1bd), [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3)]: + - @api3/airnode-protocol@0.13.0 + - @api3/airnode-validator@0.13.0 + - @api3/airnode-adapter@0.13.0 + - @api3/airnode-utilities@0.13.0 + - @api3/airnode-abi@0.13.0 + ## 0.12.0 ### Minor Changes diff --git a/packages/airnode-node/config/config.example.json b/packages/airnode-node/config/config.example.json index b4aeaeebd0..f762cd9c80 100644 --- a/packages/airnode-node/config/config.example.json +++ b/packages/airnode-node/config/config.example.json @@ -20,16 +20,16 @@ "requesterAuthorizersWithErc721": [ { "erc721s": ["0x00bDB2315678afecb367f032d93F642f64180a00"], - "RequesterAuthorizerWithErc721": "0x999DB2315678afecb367f032d93F642f64180aa9" + "RequesterAuthorizerWithErc721": "0x8e0b4538f4f6D94D3dF9b30D17E31D4C3Be9dA30" } ], "crossChainRequesterAuthorizersWithErc721": [ { "erc721s": ["0x3FbDB2315678afecb367f032d93F642f64180aa6"], "chainType": "evm", - "chainId": "5", + "chainId": "11155111", "contracts": { - "RequesterAuthorizerWithErc721": "0x6bbbb2315678afecb367f032d93F642f64180aa4" + "RequesterAuthorizerWithErc721": "0x8e0b4538f4f6D94D3dF9b30D17E31D4C3Be9dA30" }, "chainProvider": { "url": "http://127.0.0.2" @@ -80,7 +80,7 @@ }, "logFormat": "plain", "logLevel": "INFO", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "cloudProvider": { "type": "local" }, @@ -113,7 +113,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "version": "1.2.3", "title": "Currency Converter API", "apiSpecifications": { diff --git a/packages/airnode-node/package.json b/packages/airnode-node/package.json index adcddd1e64..4ab133c80f 100644 --- a/packages/airnode-node/package.json +++ b/packages/airnode-node/package.json @@ -1,7 +1,7 @@ { "name": "@api3/airnode-node", "license": "MIT", - "version": "0.12.0", + "version": "0.13.0", "private": false, "main": "dist/src/index", "types": "dist/src/index", @@ -24,14 +24,16 @@ "test:watch": "yarn test --watch" }, "dependencies": { - "@api3/airnode-abi": "^0.12.0", - "@api3/airnode-adapter": "^0.12.0", - "@api3/airnode-protocol": "^0.12.0", - "@api3/airnode-utilities": "^0.12.0", - "@api3/airnode-validator": "^0.12.0", - "@api3/ois": "2.1.0", + "@api3/airnode-abi": "^0.13.0", + "@api3/airnode-adapter": "^0.13.0", + "@api3/airnode-protocol": "^0.13.0", + "@api3/airnode-utilities": "^0.13.0", + "@api3/airnode-validator": "^0.13.0", + "@api3/chains": "^4.3.0", + "@api3/commons": "^0.5.0", + "@api3/ois": "2.3.1", "@api3/promise-utils": "^0.4.0", - "@aws-sdk/client-lambda": "^3.382.0", + "@aws-sdk/client-lambda": "^3.418.0", "date-fns": "^2.30.0", "dotenv": "^16.3.1", "ethers": "^5.7.2", @@ -39,22 +41,22 @@ "google-auth-library": "^9.0.0", "lodash": "^4.17.21", "yargs": "^17.7.2", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { - "@api3/airnode-operation": "^0.12.0", - "@types/express": "^4.17.17", - "@types/jest": "^29.5.2", - "@types/lodash": "^4.14.195", - "@types/node": "^18.16.19", - "@types/yargs": "^17.0.24", + "@api3/airnode-operation": "^0.13.0", + "@types/express": "^4.17.20", + "@types/jest": "^29.5.6", + "@types/lodash": "^4.14.200", + "@types/node": "^18.18.7", + "@types/yargs": "^17.0.29", "aws-sdk-client-mock": "^3.0.0", "aws-sdk-client-mock-jest": "^3.0.0", "copyfiles": "^2.4.1", - "jest": "^29.6.0", - "rimraf": "^5.0.1", + "jest": "^29.7.0", + "rimraf": "^5.0.5", "ts-jest": "^29.1.1", "ts-node": "^10.9.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } } diff --git a/packages/airnode-node/src/api/index.test.ts b/packages/airnode-node/src/api/index.test.ts deleted file mode 100644 index 6d5061f335..0000000000 --- a/packages/airnode-node/src/api/index.test.ts +++ /dev/null @@ -1,762 +0,0 @@ -import * as adapter from '@api3/airnode-adapter'; -import { ethers } from 'ethers'; -import { AxiosError, AxiosHeaders } from 'axios'; -import * as fixtures from '../../test/fixtures'; -import { getExpectedTemplateIdV0 } from '../evm/templates'; -import { ApiCallErrorResponse, RequestErrorMessage } from '../types'; -import { FIRST_API_CALL_TIMEOUT, SECOND_API_CALL_TIMEOUT } from '../constants'; -import { callApi, verifyTemplateId } from '.'; - -describe('callApi', () => { - fixtures.setEnvVariables({ AIRNODE_WALLET_PRIVATE_KEY: fixtures.getAirnodeWalletPrivateKey() }); - - it('calls the adapter with the given parameters', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: 1000 } }); - const requestedGasPrice = '100000000'; - const requestedMinConfirmations = '0'; - const parameters = { - _type: 'int256', - _path: 'price', - from: 'ETH', - _gasPrice: requestedGasPrice, - _minConfirmations: requestedMinConfirmations, - }; - - const [logs, res] = await callApi({ - type: 'regular', - config: fixtures.buildConfig(), - aggregatedApiCall: fixtures.buildAggregatedRegularApiCall({ parameters }), - }); - - expect(logs).toEqual([]); - expect(res).toEqual({ - success: true, - data: { - encodedValue: '0x0000000000000000000000000000000000000000000000000000000005f5e100', - signature: - '0xe92f5ee40ddb5aa42cab65fcdc025008b2bc026af80a7c93a9aac4e474f8a88f4f2bd861b9cf9a2b050bf0fd13e9714c4575cebbea658d7501e98c0963a5a38b1c', - }, - // _minConfirmations is processed before making API calls - reservedParameterOverrides: { - gasPrice: requestedGasPrice, - }, - }); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledWith( - { - endpointName: 'convertToUSD', - ois: fixtures.buildOIS(), - parameters: { from: 'ETH', amount: '1' }, - metadata: { - chainId: '31337', - chainType: 'evm', - requestId: '0xf40127616f09d41b20891bcfd326957a0e3d5a5ecf659cff4d8106c04b024374', - requesterAddress: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', - sponsorAddress: '0x2479808b1216E998309A727df8A0A98A1130A162', - sponsorWalletAddress: '0x1C1CEEF1a887eDeAB20219889971e1fd4645b55D', - }, - apiCredentials: [ - { - securitySchemeName: 'myApiSecurityScheme', - securitySchemeValue: 'supersecret', - }, - ], - }, - { timeout: FIRST_API_CALL_TIMEOUT } - ); - }); - - it('calls the adapter with the given parameters even if config.chains cannot be found', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: 1000 } }); - const parameters = { _type: 'int256', _path: 'price', from: 'ETH' }; - - const [logs, res] = await callApi({ - type: 'regular', - config: fixtures.buildConfig({ chains: [] }), - aggregatedApiCall: fixtures.buildAggregatedRegularApiCall({ parameters }), - }); - - expect(logs).toEqual([]); - expect(res).toEqual({ - success: true, - data: { - encodedValue: '0x0000000000000000000000000000000000000000000000000000000005f5e100', - signature: - '0xe92f5ee40ddb5aa42cab65fcdc025008b2bc026af80a7c93a9aac4e474f8a88f4f2bd861b9cf9a2b050bf0fd13e9714c4575cebbea658d7501e98c0963a5a38b1c', - }, - }); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledWith( - { - endpointName: 'convertToUSD', - ois: fixtures.buildOIS(), - parameters: { from: 'ETH', amount: '1' }, - metadata: { - chainId: '31337', - chainType: 'evm', - requestId: '0xf40127616f09d41b20891bcfd326957a0e3d5a5ecf659cff4d8106c04b024374', - requesterAddress: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', - sponsorAddress: '0x2479808b1216E998309A727df8A0A98A1130A162', - sponsorWalletAddress: '0x1C1CEEF1a887eDeAB20219889971e1fd4645b55D', - }, - apiCredentials: [ - { - securitySchemeName: 'myApiSecurityScheme', - securitySchemeValue: 'supersecret', - }, - ], - }, - { timeout: FIRST_API_CALL_TIMEOUT } - ); - }); - - it('calls the adapter with the given parameters with when request type is http-gateway and config just has ois and apiCredentials props', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: 1000 } }); - const parameters = { _type: 'int256', _path: 'price', from: 'ETH' }; - - const [logs, res] = await callApi({ - type: 'http-gateway', - config: { ois: [fixtures.buildOIS()], apiCredentials: [fixtures.buildApiCredentials()] }, - aggregatedApiCall: fixtures.buildAggregatedHttpGatewayApiCall({ parameters }), - }); - - expect(logs).toEqual([]); - expect(res).toEqual({ - success: true, - data: { - encodedValue: '0x0000000000000000000000000000000000000000000000000000000005f5e100', - rawValue: { price: 1000 }, - values: ['100000000'], - }, - }); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledWith( - { - endpointName: 'convertToUSD', - ois: fixtures.buildOIS(), - parameters: { from: 'ETH', amount: '1' }, - metadata: null, - apiCredentials: [ - { - securitySchemeName: 'myApiSecurityScheme', - securitySchemeValue: 'supersecret', - }, - ], - }, - { timeout: FIRST_API_CALL_TIMEOUT } - ); - }); - - it('calls the adapter with the given parameters with when request type is http-signed-data-gateway and config just has ois and apiCredentials props', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: 1000 } }); - const parameters = { _type: 'int256', _path: 'price', from: 'ETH' }; - const encodedParameters = - '0x317373730000000000000000000000000000000000000000000000000000000066726f6d0000000000000000000000000000000000000000000000000000000045544800000000000000000000000000000000000000000000000000000000005f74797065000000000000000000000000000000000000000000000000000000696e7432353600000000000000000000000000000000000000000000000000005f706174680000000000000000000000000000000000000000000000000000007072696365000000000000000000000000000000000000000000000000000000'; - const endpointId = '0x13dea3311fe0d6b84f4daeab831befbc49e19e6494c41e9e065a09c3c68f43b6'; - const templateId = '0xaa1525fe964092a826934ff09c75e1db395b947543a4ca3eb4a19628bad6c6d5'; - const [logs, res] = await callApi({ - type: 'http-signed-data-gateway', - config: { ois: [fixtures.buildOIS()], apiCredentials: [fixtures.buildApiCredentials()] }, - aggregatedApiCall: fixtures.buildAggregatedHttpSignedDataApiCall({ - endpointId, - parameters, - templateId, - template: { - airnodeAddress: '0xA30CA71Ba54E83127214D3271aEA8F5D6bD4Dace', - endpointId, - id: templateId, - encodedParameters, - }, - }), - }); - - expect(logs).toEqual([]); - expect(res).toEqual({ - success: true, - data: { - encodedValue: '0x0000000000000000000000000000000000000000000000000000000005f5e100', - signature: expect.any(String), - timestamp: expect.any(String), - }, - }); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledWith( - { - endpointName: 'convertToUSD', - ois: fixtures.buildOIS(), - parameters: { from: 'ETH', amount: '1' }, - metadata: null, - apiCredentials: [ - { - securitySchemeName: 'myApiSecurityScheme', - securitySchemeValue: 'supersecret', - }, - ], - }, - { timeout: FIRST_API_CALL_TIMEOUT } - ); - }); - - it('uses the default endpoint parameters if no user value is provided', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: 1000 } }); - - await callApi({ - type: 'regular', - config: fixtures.buildConfig(), - aggregatedApiCall: fixtures.buildAggregatedRegularApiCall(), - }); - - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledWith( - expect.objectContaining({ - parameters: { from: 'ETH', amount: '1' }, - }), - { timeout: FIRST_API_CALL_TIMEOUT } - ); - }); - - it('retries the API call if the first attempt fails', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockRejectedValueOnce(new Error('First attempt failed')); - spy.mockResolvedValueOnce({ data: { price: 1000 } }); - const requestedGasPrice = '100000000'; - const requestedMinConfirmations = '0'; - const parameters = { - _type: 'int256', - _path: 'price', - from: 'ETH', - _gasPrice: requestedGasPrice, - _minConfirmations: requestedMinConfirmations, - }; - - const [logs, res] = await callApi({ - type: 'regular', - config: fixtures.buildConfig(), - aggregatedApiCall: fixtures.buildAggregatedRegularApiCall({ parameters }), - }); - - expect(logs).toEqual([]); - expect(res).toEqual({ - success: true, - data: { - encodedValue: '0x0000000000000000000000000000000000000000000000000000000005f5e100', - signature: - '0xe92f5ee40ddb5aa42cab65fcdc025008b2bc026af80a7c93a9aac4e474f8a88f4f2bd861b9cf9a2b050bf0fd13e9714c4575cebbea658d7501e98c0963a5a38b1c', - }, - // _minConfirmations is processed before making API calls - reservedParameterOverrides: { - gasPrice: requestedGasPrice, - }, - }); - expect(spy).toHaveBeenCalledTimes(2); - expect(spy).toHaveBeenCalledWith( - { - endpointName: 'convertToUSD', - ois: fixtures.buildOIS(), - parameters: { from: 'ETH', amount: '1' }, - metadata: { - chainId: '31337', - chainType: 'evm', - requestId: '0xf40127616f09d41b20891bcfd326957a0e3d5a5ecf659cff4d8106c04b024374', - requesterAddress: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', - sponsorAddress: '0x2479808b1216E998309A727df8A0A98A1130A162', - sponsorWalletAddress: '0x1C1CEEF1a887eDeAB20219889971e1fd4645b55D', - }, - apiCredentials: [ - { - securitySchemeName: 'myApiSecurityScheme', - securitySchemeValue: 'supersecret', - }, - ], - }, - { timeout: SECOND_API_CALL_TIMEOUT } - ); - }); - - it('returns an error if the API call fails to execute', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - const nonAxiosError = new Error('A non-axios error'); - spy.mockRejectedValueOnce(nonAxiosError); - spy.mockRejectedValueOnce(nonAxiosError); - const parameters = { _type: 'int256', _path: 'unknown', from: 'ETH' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const [logs, res] = await callApi({ type: 'regular', config: fixtures.buildConfig(), aggregatedApiCall }); - expect(logs).toEqual([{ level: 'ERROR', message: 'Failed to call Endpoint:convertToUSD', error: nonAxiosError }]); - expect(res).toEqual({ - errorMessage: `${RequestErrorMessage.ApiCallFailed}`, - success: false, - }); - }); - - const internalAxiosRequestConfig = { headers: new AxiosHeaders() }; - test.each([ - { e: new AxiosError('Error!', 'CODE', internalAxiosRequestConfig, {}, undefined), msg: 'with no response' }, - { - e: new AxiosError('Error!', 'CODE', internalAxiosRequestConfig, undefined, undefined), - msg: 'in building the HTTP request', - }, - { - e: new AxiosError( - 'Error!', - 'CODE', - internalAxiosRequestConfig, - {}, - { status: 404, data: {}, statusText: '', headers: {}, config: internalAxiosRequestConfig } - ), - msg: 'with status code 404', - }, - ])(`returns an error containing "$msg" for the respective axios API call failure`, async ({ e, msg }) => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - const axiosError = e; - spy.mockRejectedValueOnce(axiosError); - spy.mockRejectedValueOnce(axiosError); - - const parameters = { _type: 'int256', _path: 'unknown', from: 'ETH' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const [logs, res] = await callApi({ type: 'regular', config: fixtures.buildConfig(), aggregatedApiCall }); - expect(logs).toEqual([{ level: 'ERROR', message: 'Failed to call Endpoint:convertToUSD', error: axiosError }]); - expect(res).toEqual({ - errorMessage: `${RequestErrorMessage.ApiCallFailed} ${msg}`, - success: false, - }); - }); - - it('returns an error if the value cannot be found with the _path', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: 1000 } }); - const parameters = { _type: 'int256', _path: 'unknown', from: 'ETH' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const [logs, res] = await callApi({ type: 'regular', config: fixtures.buildConfig(), aggregatedApiCall }); - expect(logs).toEqual([{ level: 'ERROR', message: `Unable to find value at path: 'unknown'` }]); - expect(res).toEqual({ - errorMessage: `Unable to find value at path: 'unknown'`, - success: false, - }); - }); - - it('returns an error if the value encoding fails', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: -1000 } }); - const parameters = { _type: 'uint256', _path: 'price', from: 'ETH' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const [logs, res] = await callApi({ - type: 'regular', - config: fixtures.buildConfig(), - aggregatedApiCall, - }); - - expect(logs[0].level).toEqual('ERROR'); - expect(logs[0].message).toContain('value out-of-bounds'); - - const { errorMessage, success } = res as ApiCallErrorResponse; - - expect(errorMessage).toContain('value out-of-bounds'); - expect(success).toEqual(false); - }); - - it('returns an error if the parameter type is invalid', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: '1000' } }); - const parameters = { _type: 'string', _path: 'price', from: 'ETH', test: 'new' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const [logs, res] = await callApi({ - type: 'regular', - config: fixtures.buildConfig(), - aggregatedApiCall, - }); - expect(logs).toEqual([ - { - level: 'ERROR', - message: `Parameter "_times" can only be used with numeric types, but "_type" was "${parameters._type}"`, - }, - ]); - expect(res).toEqual({ - errorMessage: `Parameter "_times" can only be used with numeric types, but "_type" was "${parameters._type}"`, - success: false, - }); - }); - - it('returns an error if the parameter type cannot be converted', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: 'string' } }); - const parameters = { _type: 'int256', _path: 'price', from: 'ETH', test: 'new' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const [logs, res] = await callApi({ - type: 'regular', - config: fixtures.buildConfig(), - aggregatedApiCall, - }); - expect(logs).toEqual([ - { - level: 'ERROR', - message: `Unable to cast value to int256`, - }, - ]); - expect(res).toEqual({ - errorMessage: `Unable to cast value to int256`, - success: false, - }); - }); - - describe('pre-processing', () => { - const createEncodedValue = (value: ethers.BigNumber, times = 100_000) => - `0x${value.mul(times).toHexString().substring(2).padStart(64, '0')}`; - - it('pre-processes parameters - valid processing code', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: 123 } }); - const parameters = { _type: 'int256', _path: 'price', from: 'TBD' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const config = fixtures.buildConfig(); - const preProcessingSpecifications = [ - { - environment: 'Node' as const, - value: 'const output = {...input, from: "BTC"};', - timeoutMs: 5_000, - }, - { - environment: 'Node' as const, - value: 'const output = {...input, source: "airnode"};', - timeoutMs: 5_000, - }, - ]; - config.ois[0].endpoints[0] = { ...config.ois[0].endpoints[0], preProcessingSpecifications }; - - const [logs, res] = await callApi({ - type: 'regular', - config, - aggregatedApiCall, - }); - - expect(logs).toEqual([]); - expect(res).toEqual({ - success: true, - data: { - encodedValue: createEncodedValue(ethers.BigNumber.from(123)), - signature: - '0xf884749942af38ef69735fcbabd1a521f7ac3b87e9988f1a57bdba10cca57f811fd43492aace34674c374a26518855c33bfb322bf5a567bac65453e67c0a4e401c', - }, - }); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledWith( - expect.objectContaining({ - parameters: { from: 'BTC', source: 'airnode', amount: '1' }, - }), - { timeout: FIRST_API_CALL_TIMEOUT } - ); - }); - - it('post-processes parameters - valid processing code', async () => { - const spy = jest.spyOn(adapter, 'buildAndExecuteRequest') as any; - spy.mockResolvedValueOnce({ data: { price: 123 } }); - const parameters = { _type: 'int256', _path: '', from: 'ETH' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const config = fixtures.buildConfig(); - const postProcessingSpecifications = [ - { - environment: 'Node' as const, - value: 'const output = parseInt(input.price)*1000;', - timeoutMs: 5_000, - }, - { - environment: 'Node' as const, - value: 'const output = parseInt(input)*2;', - timeoutMs: 5_000, - }, - ]; - config.ois[0].endpoints[0] = { ...config.ois[0].endpoints[0], postProcessingSpecifications }; - - const [logs, res] = await callApi({ - type: 'regular', - config, - aggregatedApiCall, - }); - - expect(logs).toEqual([]); - expect(res).toEqual({ - success: true, - data: { - encodedValue: createEncodedValue(ethers.BigNumber.from(123 * 1000 * 2)), - signature: - '0xb32600a43cf9f93445c9fb478ba355efa773e841b498c61218ed1a5a81a43e3d0ade6fb1a0083506c7ab3426bce45dd92d6198c136a80cdfacde839f3fcf5c8a1b', - }, - }); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledWith( - expect.objectContaining({ - parameters: { from: 'ETH', amount: '1' }, - }), - { timeout: FIRST_API_CALL_TIMEOUT } - ); - }); - }); - describe('skip API call', () => { - const createEncodedValue = (value: ethers.BigNumber, times = 100_000) => - `0x${value.mul(times).toHexString().substring(2).padStart(64, '0')}`; - - it('skips the API call with preProcessingSpecifications', async () => { - const config = fixtures.buildConfig(); - const parameters = { _type: 'int256', _path: 'result', parameter1: '25' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const preProcessingSpecifications = [ - { - environment: 'Node' as const, - value: 'const output = { result: (parseInt(input.parameter1) * 2).toString() }', - timeoutMs: 5000, - }, - ]; - - config.ois[0].endpoints[0].operation = undefined; - config.ois[0].endpoints[0].fixedOperationParameters = []; - config.ois[0].endpoints[0].preProcessingSpecifications = preProcessingSpecifications; - - const [logs, res] = await callApi({ - type: 'regular', - config, - aggregatedApiCall, - }); - - expect(logs).toEqual([]); - expect(res).toEqual({ - success: true, - data: { - encodedValue: createEncodedValue(ethers.BigNumber.from(25 * 2)), - signature: - '0x148d65210b201c3ddd6f8e08cfc29032e9f3c781919eeb80b950dbb984ebbbee289105ea8b591ace166d04b65e334801ea0177bb431775db2b4268d55fa4e2a81c', - }, - }); - }); - - it('skips the API call with postProcessingSpecifications', async () => { - const config = fixtures.buildConfig(); - const parameters = { _type: 'int256', _path: 'result', parameter1: '25' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const postProcessingSpecifications = [ - { - environment: 'Node' as const, - value: 'const output = { result: (parseInt(input.parameter1) * 2).toString() }', - timeoutMs: 5000, - }, - ]; - - config.ois[0].endpoints[0].operation = undefined; - config.ois[0].endpoints[0].fixedOperationParameters = []; - config.ois[0].endpoints[0].postProcessingSpecifications = postProcessingSpecifications; - - const [logs, res] = await callApi({ - type: 'regular', - config, - aggregatedApiCall, - }); - - expect(logs).toEqual([]); - expect(res).toEqual({ - success: true, - data: { - encodedValue: createEncodedValue(ethers.BigNumber.from(25 * 2)), - signature: - '0x148d65210b201c3ddd6f8e08cfc29032e9f3c781919eeb80b950dbb984ebbbee289105ea8b591ace166d04b65e334801ea0177bb431775db2b4268d55fa4e2a81c', - }, - }); - }); - - it('skips API call with both preProcessingSpecifications and postProcessingSpecifications', async () => { - const config = fixtures.buildConfig(); - const parameters = { _type: 'int256', _path: 'result', parameter1: '25' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - const preProcessingSpecifications = [ - { - environment: 'Node' as const, - value: 'const output = {...input, addThis: "5" }', - timeoutMs: 5000, - }, - ]; - const postProcessingSpecifications = [ - { - environment: 'Node' as const, - value: 'const output = { result: (parseInt(input.parameter1) * 2 + parseInt(input.addThis)).toString() }', - timeoutMs: 5000, - }, - ]; - - config.ois[0].endpoints[0].operation = undefined; - config.ois[0].endpoints[0].fixedOperationParameters = []; - config.ois[0].endpoints[0].preProcessingSpecifications = preProcessingSpecifications; - config.ois[0].endpoints[0].postProcessingSpecifications = postProcessingSpecifications; - - const [logs, res] = await callApi({ - type: 'regular', - config, - aggregatedApiCall, - }); - - expect(logs).toEqual([]); - expect(res).toEqual({ - success: true, - data: { - encodedValue: createEncodedValue(ethers.BigNumber.from(25 * 2 + 5)), - signature: - '0x9796e8ba07c517a43b2ca1416b9c975541345c5b7bf73613738ed84216c4573d1656cbc385acb9111b7077fba65418b59cfe3f59ee81109523664bbc25efcfd71b', - }, - }); - }); - - it('fails when both preProcessingSpecifications and postProcessingSpecifications are empty', async () => { - const config = fixtures.buildConfig(); - const parameters = { _type: 'int256', _path: 'result', parameter1: '25' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - - config.ois[0].endpoints[0].operation = undefined; - config.ois[0].endpoints[0].fixedOperationParameters = []; - config.ois[0].endpoints[0].preProcessingSpecifications = []; - config.ois[0].endpoints[0].postProcessingSpecifications = []; - - const [logs, res] = await callApi({ - type: 'regular', - config, - aggregatedApiCall, - }); - - expect(logs).toEqual([ - { - level: 'ERROR', - message: - "Failed to skip API call. Ensure at least one of 'preProcessingSpecifications' or 'postProcessingSpecifications' is defined and is not an empty array at ois 'Currency Converter API', endpoint 'convertToUSD'.", - }, - ]); - expect(res).toEqual({ - success: false, - errorMessage: `Failed to skip API call. Ensure at least one of 'preProcessingSpecifications' or 'postProcessingSpecifications' is defined and is not an empty array at ois 'Currency Converter API', endpoint 'convertToUSD'.`, - }); - }); - - it('fails when both preProcessingSpecifications and postProcessingSpecifications are undefined', async () => { - const config = fixtures.buildConfig(); - const parameters = { _type: 'int256', _path: 'result', parameter1: '25' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - - config.ois[0].endpoints[0].operation = undefined; - config.ois[0].endpoints[0].fixedOperationParameters = []; - config.ois[0].endpoints[0].preProcessingSpecifications = undefined; - config.ois[0].endpoints[0].postProcessingSpecifications = undefined; - - const [logs, res] = await callApi({ - type: 'regular', - config, - aggregatedApiCall, - }); - - expect(logs).toEqual([ - { - level: 'ERROR', - message: - "Failed to skip API call. Ensure at least one of 'preProcessingSpecifications' or 'postProcessingSpecifications' is defined and is not an empty array at ois 'Currency Converter API', endpoint 'convertToUSD'.", - }, - ]); - expect(res).toEqual({ - success: false, - errorMessage: `Failed to skip API call. Ensure at least one of 'preProcessingSpecifications' or 'postProcessingSpecifications' is defined and is not an empty array at ois 'Currency Converter API', endpoint 'convertToUSD'.`, - }); - }); - }); -}); - -describe('verifyTemplateId', () => { - const validTemplateFields = { - airnodeAddress: '0x5FbDB2315678afecb367f032d93F642f64180aa3', - endpointId: '0x2f3a3adf6daf5a3bb00ab83aa82262a6a84b59b0a89222386135330a1819ab48', - encodedParameters: '0x6466726f6d63455448', - }; - - const TEMPLATE_ID = '0xb2f063157fcc3c986daf4c2cf1b8ac8b8843f2b1a54c5de5e1ebdf12fb85a927'; - - it('returns API calls not linked to templates', () => { - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ templateId: null }); - const config = fixtures.buildConfig(); - - const response = verifyTemplateId({ type: 'regular', aggregatedApiCall, config }); - - expect(response).toEqual(null); - }); - - it('ignores API calls where the template cannot be found', () => { - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ - templateId: TEMPLATE_ID, - template: undefined, - }); - const config = fixtures.buildConfig(); - - const response = verifyTemplateId({ type: 'regular', aggregatedApiCall, config }); - - expect(response).toEqual([ - [ - { - level: 'ERROR', - message: `Ignoring Request:${aggregatedApiCall.id} as the template could not be found for verification`, - }, - ], - { - errorMessage: `Ignoring Request:${aggregatedApiCall.id} as the template could not be found for verification`, - success: false, - }, - ]); - }); - - it('does nothing where API calls are linked to a valid templated', () => { - const template = fixtures.requests.buildApiCallTemplate({ - ...validTemplateFields, - id: TEMPLATE_ID, - }); - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ - templateId: TEMPLATE_ID, - template, - }); - const config = fixtures.buildConfig(); - - const response = verifyTemplateId({ type: 'regular', aggregatedApiCall, config }); - - expect(response).toEqual(null); - }); - - describe('invalid fields', () => { - const validTemplate = fixtures.requests.buildApiCallTemplate({ - ...validTemplateFields, - id: TEMPLATE_ID, - }); - const config = fixtures.buildConfig(); - const invalidFields = { - airnodeAddress: '0x69e2B095fbAc6C3f9E528Ef21882b86BF1595181', - endpointId: '0x05218bc3e2497776d24b7da2890e12c910d07ce647cc45bd565cbb167e620df3', - encodedParameters: '0x1234', - }; - - Object.keys(invalidFields).forEach((field) => { - it(`is invalid if ${field} has been changed`, () => { - const invalidTemplate = { ...validTemplate, [field]: (invalidFields as any)[field] }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ - templateId: TEMPLATE_ID, - template: invalidTemplate, - }); - const expectedTemplateId = getExpectedTemplateIdV0(invalidTemplate); - const response = verifyTemplateId({ type: 'regular', aggregatedApiCall, config }); - expect(response).toEqual([ - [ - { - level: 'ERROR', - message: `Invalid template ID:${TEMPLATE_ID} found for Request:${aggregatedApiCall.id}. Expected template ID:${expectedTemplateId}`, - }, - ], - { - errorMessage: `Invalid template ID:${TEMPLATE_ID} found for Request:${aggregatedApiCall.id}. Expected template ID:${expectedTemplateId}`, - success: false, - }, - ]); - }); - }); - }); -}); diff --git a/packages/airnode-node/src/api/index.ts b/packages/airnode-node/src/api/index.ts index bb8a1aa1d4..eadf2e0e85 100644 --- a/packages/airnode-node/src/api/index.ts +++ b/packages/airnode-node/src/api/index.ts @@ -1,15 +1,15 @@ import * as adapter from '@api3/airnode-adapter'; import isEmpty from 'lodash/isEmpty'; -import { OIS, RESERVED_PARAMETERS, Endpoint } from '@api3/ois'; +import { RESERVED_PARAMETERS } from '@api3/ois'; +import { preProcessEndpointParameters, postProcessResponse } from '@api3/commons'; import { logger, removeKeys, removeKey } from '@api3/airnode-utilities'; import { go, goSync } from '@api3/promise-utils'; import axios, { AxiosError } from 'axios'; import { ethers } from 'ethers'; import compact from 'lodash/compact'; -import { postProcessApiSpecifications, preProcessApiSpecifications } from './processing'; import { getAirnodeWalletFromPrivateKey } from '../evm'; import { getReservedParameters } from '../adapters/http/parameters'; -import { FIRST_API_CALL_TIMEOUT, SECOND_API_CALL_TIMEOUT } from '../constants'; +import { FIRST_API_CALL_TIMEOUT, PROCESSING_TIMEOUT, SECOND_API_CALL_TIMEOUT } from '../constants'; import { isValidRequestId } from '../evm/verification'; import { getExpectedTemplateIdV0, getExpectedTemplateIdV1 } from '../evm/templates'; import { @@ -151,10 +151,13 @@ export function verifyCallApi(payload: ApiCallPayload) { export function verifyRegularCallApiParams(payload: RegularApiCallPayload) { const verifications = [verifyRequestId, verifyTemplateId]; - return verifications.reduce((result, verifierFn) => { - if (result) return result; - return verifierFn(payload); - }, null as LogsData | null); + return verifications.reduce( + (result, verifierFn) => { + if (result) return result; + return verifierFn(payload); + }, + null as LogsData | null + ); } export function verifyHttpSignedCallApiParams(payload: HttpSignedApiCallPayload) { @@ -220,15 +223,18 @@ export async function processSuccessfulApiCall( const { _type, _path, _times, _gasPrice } = getReservedParameters(endpoint, parameters); const goPostProcessApiSpecifications = await go(() => - postProcessApiSpecifications(rawResponse.data, endpoint, payload) + postProcessResponse(rawResponse.data, endpoint, aggregatedApiCall.parameters, { + totalTimeoutMs: PROCESSING_TIMEOUT, + }) ); if (!goPostProcessApiSpecifications.success) { const log = logger.pend('ERROR', goPostProcessApiSpecifications.error.message); return [[log], { success: false, errorMessage: goPostProcessApiSpecifications.error.message }]; } + const postProcessedData = goPostProcessApiSpecifications.data; const goExtractAndEncodeResponse = goSync(() => - adapter.extractAndEncodeResponse(goPostProcessApiSpecifications.data, { + adapter.extractAndEncodeResponse(postProcessedData.response, { _type, _path, _times, @@ -237,7 +243,7 @@ export async function processSuccessfulApiCall( if (!goExtractAndEncodeResponse.success) { const log = logger.pend('ERROR', goExtractAndEncodeResponse.error.message); // The HTTP gateway is a special case for ChainAPI where we return data from a successful API call that failed processing - if (payload.type === 'http-gateway') { + if (type === 'http-gateway') { return [ [log], { success: true, errorMessage: goExtractAndEncodeResponse.error.message, data: { rawValue: rawResponse.data } }, @@ -268,7 +274,7 @@ export async function processSuccessfulApiCall( ]; } case 'http-signed-data-gateway': { - const timestamp = Math.floor(Date.now() / 1000).toString(); + const timestamp = (postProcessedData.timestamp ?? Math.floor(Date.now() / 1000)).toString(); const goSignWithTemplateId = await go(() => signWithTemplateId(aggregatedApiCall.templateId, timestamp, response.encodedValue) ); @@ -292,24 +298,27 @@ export async function callApi(payload: ApiCallPayload): Promise o.title === payload.aggregatedApiCall.oisTitle)!; - const endpoint = ois.endpoints.find((e: Endpoint) => e.name === payload.aggregatedApiCall.endpointName)!; + const { + aggregatedApiCall: { parameters }, + } = payload; + const ois = payload.config.ois.find((o) => o.title === payload.aggregatedApiCall.oisTitle)!; + const endpoint = ois.endpoints.find((e) => e.name === payload.aggregatedApiCall.endpointName)!; + const { endpointParameters: processedEndpointParameters } = await preProcessEndpointParameters(endpoint, parameters, { + totalTimeoutMs: PROCESSING_TIMEOUT, + }); - // skip API call if operation is undefined and fixedOperationParameters is empty array + // Skip API call if operation is undefined and fixedOperationParameters is empty array. We can be sure that there is + // at least one processing specification defined (either v1 or v2) because it is verified by the OIS schema. if (!endpoint.operation && isEmpty(endpoint.fixedOperationParameters)) { - // contents of preProcessingSpecifications or postProcessingSpecifications (or both) will simulate an API when API call is skipped - if (isEmpty(endpoint.preProcessingSpecifications) && isEmpty(endpoint.postProcessingSpecifications)) { - const message = `Failed to skip API call. Ensure at least one of 'preProcessingSpecifications' or 'postProcessingSpecifications' is defined and is not an empty array at ois '${payload.aggregatedApiCall.oisTitle}', endpoint '${payload.aggregatedApiCall.endpointName}'.`; - const log = logger.pend('ERROR', message); - return [[log], { success: false, errorMessage: message }]; - } - // output of preProcessingSpecifications can be used as output directly or - // preProcessingSpecifications can be used to manipulate parameters to use in postProcessingSpecifications - return processSuccessfulApiCall(payload, { data: processedPayload.aggregatedApiCall.parameters }); + // The pre-processing output can be used as output directly or it can be used to manipulate parameters to use in + // post-processing. + return processSuccessfulApiCall(payload, { data: processedEndpointParameters }); } - const [logs, response] = await performApiCall(processedPayload); + const [logs, response] = await performApiCall({ + ...payload, + aggregatedApiCall: { ...payload.aggregatedApiCall, parameters: processedEndpointParameters }, + } as ApiCallPayload); if (isPerformApiCallFailure(response)) { return [logs, response]; } diff --git a/packages/airnode-node/src/api/processing.test.ts b/packages/airnode-node/src/api/processing.test.ts deleted file mode 100644 index 5bb6228582..0000000000 --- a/packages/airnode-node/src/api/processing.test.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { postProcessApiSpecifications, preProcessApiSpecifications } from './processing'; -import * as fixtures from '../../test/fixtures'; - -describe('pre-processing', () => { - it('valid processing code', async () => { - const config = fixtures.buildConfig(); - const preProcessingSpecifications = [ - { - environment: 'Node' as const, - value: 'const output = {...input, from: "ETH"};', - timeoutMs: 5_000, - }, - { - environment: 'Node' as const, - value: 'const output = {...input, newProp: "airnode"};', - timeoutMs: 5_000, - }, - ]; - config.ois[0].endpoints[0] = { ...config.ois[0].endpoints[0], preProcessingSpecifications }; - - const parameters = { _type: 'int256', _path: 'price' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - - const result = await preProcessApiSpecifications({ type: 'regular', config, aggregatedApiCall }); - - expect(result.aggregatedApiCall.parameters).toEqual({ - _path: 'price', - _type: 'int256', - from: 'ETH', - newProp: 'airnode', - }); - }); - - it('invalid processing code', async () => { - const config = fixtures.buildConfig(); - const preProcessingSpecifications = [ - { - environment: 'Node' as const, - value: 'something invalid; const output = {...input, from: `ETH`};', - timeoutMs: 5_000, - }, - { - environment: 'Node' as const, - value: 'const output = {...input, newProp: "airnode"};', - timeoutMs: 5_000, - }, - ]; - config.ois[0].endpoints[0] = { ...config.ois[0].endpoints[0], preProcessingSpecifications }; - - const parameters = { _type: 'int256', _path: 'price', from: 'TBD' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - - const throwingFunc = () => preProcessApiSpecifications({ type: 'regular', config, aggregatedApiCall }); - - await expect(throwingFunc).rejects.toEqual(new Error('SyntaxError: Unexpected identifier')); - }); - - it('demonstrates access to endPointParameters, but reserved parameters are inaccessible', async () => { - const config = fixtures.buildConfig(); - const preProcessingSpecifications = [ - { - environment: 'Node' as const, - // pretend the user is trying to 1) override _path and 2) set a new parameter based on - // the presence of the reserved parameter _type (which is inaccessible) - value: - 'const output = {...input, from: "ETH", _path: "price.newpath", myVal: input._type ? "123" : "456", newTo: endpointParameters.to };', - timeoutMs: 5_000, - }, - ]; - config.ois[0].endpoints[0] = { ...config.ois[0].endpoints[0], preProcessingSpecifications }; - - const parameters = { _type: 'int256', _path: 'price', to: 'USD' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - - const result = await preProcessApiSpecifications({ type: 'http-gateway', config, aggregatedApiCall }); - - expect(result.aggregatedApiCall.parameters).toEqual({ - _path: 'price', // is not overridden - _type: 'int256', - from: 'ETH', // originates from the processing code - to: 'USD', // should be unchanged from the original parameters - myVal: '456', // is set to "456" because _type is not present in the environment - newTo: 'USD', // demonstrates access to endpointParameters - }); - }); -}); - -describe('post-processing', () => { - it('processes valid code', async () => { - const config = fixtures.buildConfig(); - const postProcessingSpecifications = [ - { - environment: 'Node' as const, - value: 'const output = parseInt(input.price)*2;', - timeoutMs: 5_000, - }, - { - environment: 'Node' as const, - value: 'const output = parseInt(input)*2;', - timeoutMs: 5_000, - }, - ]; - const endpoint = { ...config.ois[0].endpoints[0], postProcessingSpecifications }; - const parameters = { _type: 'int256', _path: 'price' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - - const result = await postProcessApiSpecifications({ price: 1000 }, endpoint, { - type: 'http-gateway', - config, - aggregatedApiCall, - }); - - expect(result).toEqual(4000); - }); - - it('demonstrates access to endPointParameters, but reserved parameters are inaccessible', async () => { - const config = fixtures.buildConfig(); - const postProcessingSpecifications = [ - { - environment: 'Node' as const, - value: - 'const reservedMultiplier = endpointParameters._times ? 1 : 2; const output = parseInt(input.price) * endpointParameters.myMultiplier * reservedMultiplier;', - timeoutMs: 5_000, - }, - ]; - const endpoint = { ...config.ois[0].endpoints[0], postProcessingSpecifications }; - const myMultiplier = 10; - const parameters = { _type: 'int256', _path: 'price', myMultiplier }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - - const price = 1000; - const result = await postProcessApiSpecifications({ price }, endpoint, { - type: 'http-gateway', - config, - aggregatedApiCall, - }); - - // reserved parameters (_times) should be inaccessible to post-processing for the - // http-gateway, hence multiplication by 2 instead of 1 - expect(result).toEqual(price * myMultiplier * 2); - }); - - it('throws on invalid code', async () => { - const config = fixtures.buildConfig(); - const postProcessingSpecifications = [ - { - environment: 'Node' as const, - value: 'const output = parseInt(input.price)*1000;', - timeoutMs: 5_000, - }, - { - environment: 'Node' as const, - value: 'Something Unexpected; const output = parseInt(input)*2;', - timeoutMs: 5_000, - }, - ]; - const endpoint = { ...config.ois[0].endpoints[0], postProcessingSpecifications }; - const parameters = { _type: 'int256', _path: 'price' }; - const aggregatedApiCall = fixtures.buildAggregatedRegularApiCall({ parameters }); - - const throwingFunc = () => - postProcessApiSpecifications({ price: 1000 }, endpoint, { - type: 'http-gateway', - config, - aggregatedApiCall, - }); - - await expect(throwingFunc).rejects.toEqual(new Error('SyntaxError: Unexpected identifier')); - }); -}); diff --git a/packages/airnode-node/src/api/processing.ts b/packages/airnode-node/src/api/processing.ts deleted file mode 100644 index 06727a2c6b..0000000000 --- a/packages/airnode-node/src/api/processing.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { Endpoint, ProcessingSpecification, RESERVED_PARAMETERS } from '@api3/ois'; -import { go } from '@api3/promise-utils'; -import { unsafeEvaluate, unsafeEvaluateAsync } from './unsafe-evaluate'; -import { apiCallParametersSchema } from '../validation'; -import { PROCESSING_TIMEOUT } from '../constants'; -import { ApiCallParameters, ApiCallPayload } from '../types'; - -const reservedParameters = RESERVED_PARAMETERS as string[]; - -const removeReservedParameters = (parameters: ApiCallParameters): ApiCallParameters => { - return Object.fromEntries(Object.entries(parameters).filter(([key]) => !reservedParameters.includes(key))); -}; - -/** - * Re-inserts reserved parameters from the initial parameters object into the modified parameters object. - */ -const reInsertReservedParameters = ( - initialParameters: ApiCallParameters, - modifiedParameters: ApiCallParameters -): ApiCallParameters => { - return Object.entries(initialParameters).reduce( - (params, [key, value]) => (reservedParameters.includes(key) ? { ...params, [key]: value } : params), - modifiedParameters - ); -}; - -export const preProcessApiSpecifications = async (payload: ApiCallPayload): Promise => { - const { config, aggregatedApiCall } = payload; - const { endpointName, oisTitle } = aggregatedApiCall; - const ois = config.ois.find((o) => o.title === oisTitle)!; - const { preProcessingSpecifications } = ois.endpoints.find((e) => e.name === endpointName)!; - - if (!preProcessingSpecifications || preProcessingSpecifications.length === 0) { - return payload; - } - - const inputParameters = removeReservedParameters(aggregatedApiCall.parameters); - - const goProcessedParameters = await go( - () => - preProcessingSpecifications.reduce(async (input: Promise, currentValue: ProcessingSpecification) => { - // provide endpoint parameters without reserved parameters immutably between steps - const endpointParameters = removeReservedParameters( - JSON.parse(JSON.stringify(payload.aggregatedApiCall.parameters)) - ); - switch (currentValue.environment) { - case 'Node': - return unsafeEvaluate(await input, currentValue.value, currentValue.timeoutMs, endpointParameters); - case 'Node async': - return unsafeEvaluateAsync(await input, currentValue.value, currentValue.timeoutMs, endpointParameters); - default: - throw new Error(`Environment ${currentValue.environment} is not supported`); - } - }, Promise.resolve(inputParameters)), - { retries: 0, totalTimeoutMs: PROCESSING_TIMEOUT } - ); - - if (!goProcessedParameters.success) { - throw goProcessedParameters.error; - } - - // Let this throw if the processed parameters are invalid - const parsedParameters = apiCallParametersSchema.parse(goProcessedParameters.data); - - // Having removed reserved parameters for pre-processing, we need to re-insert them for the API call - const parameters = reInsertReservedParameters(aggregatedApiCall.parameters, parsedParameters); - - return { - ...payload, - aggregatedApiCall: { - ...aggregatedApiCall, - parameters, - }, - } as ApiCallPayload; -}; - -export const postProcessApiSpecifications = async (input: unknown, endpoint: Endpoint, payload: ApiCallPayload) => { - const { postProcessingSpecifications } = endpoint; - - if (!postProcessingSpecifications || postProcessingSpecifications?.length === 0) { - return input; - } - - const goResult = await go( - () => - postProcessingSpecifications.reduce(async (input: any, currentValue: ProcessingSpecification) => { - // provide endpoint parameters without reserved parameters immutably between steps - const endpointParameters = removeReservedParameters( - JSON.parse(JSON.stringify(payload.aggregatedApiCall.parameters)) - ); - switch (currentValue.environment) { - case 'Node': - return unsafeEvaluate(await input, currentValue.value, currentValue.timeoutMs, endpointParameters); - case 'Node async': - return unsafeEvaluateAsync(await input, currentValue.value, currentValue.timeoutMs, endpointParameters); - default: - throw new Error(`Environment ${currentValue.environment} is not supported`); - } - }, Promise.resolve(input)), - - { retries: 0, totalTimeoutMs: PROCESSING_TIMEOUT } - ); - - if (!goResult.success) { - throw goResult.error; - } - - return goResult.data; -}; diff --git a/packages/airnode-node/src/api/unsafe-evaluate.test.ts b/packages/airnode-node/src/api/unsafe-evaluate.test.ts deleted file mode 100644 index 752685938f..0000000000 --- a/packages/airnode-node/src/api/unsafe-evaluate.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { unsafeEvaluate, unsafeEvaluateAsync } from './unsafe-evaluate'; - -describe('unsafe evaluate - sync', () => { - it('executes harmless code', () => { - const result = unsafeEvaluate({ a: true, b: 123 }, "const output = {...input, c: 'some-value'}", 5_000); - - expect(result).toEqual({ a: true, b: 123, c: 'some-value' }); - }); - - it('throws on exception', () => { - expect(() => unsafeEvaluate({}, "throw new Error('unexpected')", 5_000)).toThrow('unexpected'); - }); -}); - -describe('unsafe evaluate - async', () => { - it('executes harmless code', async () => { - const result = unsafeEvaluateAsync( - { a: true, b: 123 }, - "const output = {...input, c: 'some-value'}; resolve(output);", - 5_000 - ); - - await expect(result).resolves.toEqual({ a: true, b: 123, c: 'some-value' }); - }); - - it('can use setTimeout and setInterval', async () => { - const result = unsafeEvaluateAsync( - [], - ` - const fn = async () => { - const output = input; - output.push('start') - - const tickMs = 35 - const bufferMs = 25 - setInterval(() => output.push('ping interval'), tickMs) - await new Promise((res) => setTimeout(res, tickMs * 4 + bufferMs)); - - output.push('end') - resolve(output); - }; - - fn() - `, - 200 - ); - - await expect(result).resolves.toEqual([ - 'start', - 'ping interval', - 'ping interval', - 'ping interval', - 'ping interval', - 'end', - ]); - }); - - it('applies timeout when using setTimeout', async () => { - await expect(() => - unsafeEvaluateAsync( - {}, - ` - const fn = () => { - setTimeout(() => console.log('ping timeout'), 100) - }; - - fn() - `, - 50 - ) - ).rejects.toEqual(new Error('Timeout exceeded')); - }); - - it('applies timeout when using setInterval', async () => { - await expect(() => - unsafeEvaluateAsync( - {}, - ` - const fn = () => { - const someFn = () => {} - setInterval(someFn, 10) - }; - - fn() - `, - 50 - ) - ).rejects.toEqual(new Error('Timeout exceeded')); - }); - - it('processing can call reject', async () => { - await expect(() => - unsafeEvaluateAsync({}, `reject(new Error('Rejected by processing snippet.'))`, 50) - ).rejects.toEqual(new Error('Rejected by processing snippet.')); - }); - - it('throws on exception', async () => { - await expect(() => unsafeEvaluateAsync({}, "throw new Error('unexpected')", 5_000)).rejects.toEqual( - new Error('unexpected') - ); - }); -}); diff --git a/packages/airnode-node/src/api/unsafe-evaluate.ts b/packages/airnode-node/src/api/unsafe-evaluate.ts deleted file mode 100644 index 79f416aa35..0000000000 --- a/packages/airnode-node/src/api/unsafe-evaluate.ts +++ /dev/null @@ -1,146 +0,0 @@ -import assert from 'assert'; -import async_hooks from 'async_hooks'; -import buffer from 'buffer'; -import child_process from 'child_process'; -import cluster from 'cluster'; -import console from 'console'; -import constants from 'constants'; -import crypto from 'crypto'; -import dgram from 'dgram'; -import dns from 'dns'; -import events from 'events'; -import fs from 'fs'; -import http from 'http'; -import http2 from 'http2'; -import https from 'https'; -import inspector from 'inspector'; -import module from 'module'; -import net from 'net'; -import os from 'os'; -import path from 'path'; -import perf_hooks from 'perf_hooks'; -import process from 'process'; -import readline from 'readline'; -import repl from 'repl'; -import stream from 'stream'; -import string_decoder from 'string_decoder'; -import timers from 'timers'; -import tls from 'tls'; -import trace_events from 'trace_events'; -import tty from 'tty'; -import url from 'url'; -import util from 'util'; -import v8 from 'v8'; -import vm from 'vm'; -import worker_threads from 'worker_threads'; -import zlib from 'zlib'; -import { createTimers } from './vm-timers'; - -const builtInNodeModules = { - assert, - async_hooks, - buffer, - child_process, - cluster, - console, - constants, - crypto, - dgram, - dns, - events, - fs, - http, - http2, - https, - inspector, - module, - net, - os, - path, - perf_hooks, - process, - readline, - repl, - stream, - string_decoder, - timers, - tls, - trace_events, - tty, - url, - util, - v8, - vm, - worker_threads, - zlib, -}; - -/** - * This function is dangerous. Make sure to use it only with Trusted code. - */ -export const unsafeEvaluate = (input: any, code: string, timeout: number, endpointParameters?: any) => { - const vmContext = { - input, - endpointParameters, - ...builtInNodeModules, - deferredOutput: undefined, - }; - - vm.runInNewContext(`${code}; deferredOutput = output;`, vmContext, { - displayErrors: true, - timeout, - }); - - return vmContext.deferredOutput; -}; - -/** - * This function runs asynchronous code in a Node VM. - - * @code should be written as ({input, resolve}) => {something; resolve({...input, something: 1})}; - * Refer to vmContext here for what's available. - * - * Some libraries one might expect to be available may not necessarily be available in cloud environments due to - * being stripped out by webpack. In these cases these libraries may need to be minified and included in the `code` - * payload. - * - * The value given to `resolve` is expected to be the equivalent of `output` above. - */ -export const unsafeEvaluateAsync = (input: any, code: string, timeout: number, endpointParameters?: any) => { - let vmReject: (reason: unknown) => void; - - // Make sure the timeout is applied. When the processing snippet uses setTimeout or setInterval, the timeout option - // from VM is broken. See: https://github.com/nodejs/node/issues/3020. - // - // We need to manually clear all timers and reject the processing manually. - const timeoutTimer = setTimeout(() => { - vmReject(new Error('Timeout exceeded')); - }, timeout); - - return new Promise((evaluateResolve, evaluateReject) => { - const timers = createTimers(); - const vmResolve = (value: unknown) => { - timers.clearAll(); - clearTimeout(timeoutTimer); - evaluateResolve(value); - }; - vmReject = (reason: unknown) => { - timers.clearAll(); - clearTimeout(timeoutTimer); - evaluateReject(reason); - }; - - const vmContext = { - input, - endpointParameters, - resolve: vmResolve, - reject: vmReject, - setTimeout: timers.customSetTimeout, - setInterval: timers.customSetInterval, - clearTimeout: timers.customClearTimeout, - clearInterval: timers.customClearInterval, - ...builtInNodeModules, - }; - vm.runInNewContext(code, vmContext, { displayErrors: true, timeout }); - }); -}; diff --git a/packages/airnode-node/src/api/vm-timers.ts b/packages/airnode-node/src/api/vm-timers.ts deleted file mode 100644 index 29b27f1e93..0000000000 --- a/packages/airnode-node/src/api/vm-timers.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Timers (setTimeout, setInterval) do not work in Node.js vm, see: https://github.com/nodejs/help/issues/1875 - * - * The API is wrapped in a "create" function so that every processing snippet keeps track of its timers and properly - * cleans them up after use. - */ -export const createTimers = () => { - let timeouts: NodeJS.Timer[] = []; - - const customSetTimeout = (fn: () => void, ms: number) => { - timeouts.push(setTimeout(fn, ms)); - }; - - const customClearTimeout = (id: NodeJS.Timer) => { - timeouts = timeouts.filter((timeoutId) => timeoutId !== id); - clearTimeout(id); - }; - - const clearAllTimeouts = () => { - timeouts.forEach(clearTimeout); - timeouts = []; - }; - - let intervals: NodeJS.Timer[] = []; - - const customSetInterval = (fn: () => void, ms: number) => { - intervals.push(setInterval(fn, ms)); - }; - - const customClearInterval = (id: NodeJS.Timer) => { - intervals = intervals.filter((intervalId) => intervalId !== id); - clearInterval(id); - }; - - const clearAllIntervals = () => { - intervals.forEach(clearInterval); - intervals = []; - }; - - const clearAll = () => { - clearAllTimeouts(); - clearAllIntervals(); - }; - - return { - customSetTimeout, - customClearTimeout, - clearAllTimeouts, - customSetInterval, - customClearInterval, - clearAllIntervals, - clearAll, - }; -}; diff --git a/packages/airnode-node/src/cli/http-signed-data-invoke.ts b/packages/airnode-node/src/cli/http-signed-data-invoke.ts index c57855337c..4fec47dabf 100644 --- a/packages/airnode-node/src/cli/http-signed-data-invoke.ts +++ b/packages/airnode-node/src/cli/http-signed-data-invoke.ts @@ -29,10 +29,6 @@ yargs(hideBin(process.argv)) async (args) => { logger.log(`Invoke HTTP signed data handler`); const config = loadTrustedConfig(path.resolve(`${__dirname}/../../config/config.json`), process.env); - const parameters = JSON.parse(args.encodedParameters); - if (!parameters) { - throw new Error('Missing request parameters'); - } logger.log( JSON.stringify(await processHttpSignedDataRequest(config, args['endpoint-id'], args['encoded-parameters'])) ); diff --git a/packages/airnode-node/src/config/index.test.ts b/packages/airnode-node/src/config/index.test.ts index 5f07ac047a..7e7240002a 100644 --- a/packages/airnode-node/src/config/index.test.ts +++ b/packages/airnode-node/src/config/index.test.ts @@ -13,7 +13,7 @@ describe('config validation', () => { const exampleSecrets = dotenv.parse(readFileSync(join(__dirname, '../../config/secrets.example.env'))); it('loads the config and adds default contract addresses', () => { - const chainId = '5'; + const chainId = '11155111'; const invalidConfig = JSON.parse(readFileSync(exampleConfigPath, 'utf-8')); invalidConfig.chains[0].id = chainId; // Need to use an actual chain not hardhat delete invalidConfig.chains[0].contracts; diff --git a/packages/airnode-node/src/coordinator/calls/coordinated-execution.ts b/packages/airnode-node/src/coordinator/calls/coordinated-execution.ts index 3887040a2d..5d5babe05a 100644 --- a/packages/airnode-node/src/coordinator/calls/coordinated-execution.ts +++ b/packages/airnode-node/src/coordinator/calls/coordinated-execution.ts @@ -85,7 +85,7 @@ export async function callApis( const pendingAggregatedCalls = aggregatedApiCalls.filter((a) => !a.errorMessage); const skippedAggregatedCalls = aggregatedApiCalls .filter((a) => a.errorMessage) - .map((a) => ({ ...a, success: false, errorMessage: a.errorMessage! } as const)); + .map((a) => ({ ...a, success: false, errorMessage: a.errorMessage! }) as const); if (isEmpty(pendingAggregatedCalls)) { const log = logger.pend('INFO', 'No pending API calls to process. Skipping API calls...'); diff --git a/packages/airnode-node/src/evm/evm-provider.ts b/packages/airnode-node/src/evm/evm-provider.ts index db484920d7..7640d9cc26 100644 --- a/packages/airnode-node/src/evm/evm-provider.ts +++ b/packages/airnode-node/src/evm/evm-provider.ts @@ -1,13 +1,15 @@ import { ethers } from 'ethers'; -import { networks } from '@api3/airnode-protocol'; +import { CHAINS } from '@api3/chains'; import { EVM_PROVIDER_TIMEOUT } from '../constants'; export function buildEVMProvider(url: string, chainId: string) { // Ethers makes a call to get the network in the background if it is // not provided/undefined when initializing the provider. We keep // a list of "known" networks to stop these extra calls if possible. - const network = networks[chainId] || null; + + const network = CHAINS.find((network) => network.id === chainId); + const ethersNetwork = network ? { name: network.alias, chainId: parseInt(network.id) } : undefined; // Ethers only let's us configure the timeout when creating a provider - return new ethers.providers.StaticJsonRpcProvider({ url, timeout: EVM_PROVIDER_TIMEOUT }, network); + return new ethers.providers.StaticJsonRpcProvider({ url, timeout: EVM_PROVIDER_TIMEOUT }, ethersNetwork); } diff --git a/packages/airnode-node/src/evm/fulfillments/api-calls.test.ts b/packages/airnode-node/src/evm/fulfillments/api-calls.test.ts index 896eabc13d..4b05b52765 100644 --- a/packages/airnode-node/src/evm/fulfillments/api-calls.test.ts +++ b/packages/airnode-node/src/evm/fulfillments/api-calls.test.ts @@ -35,7 +35,7 @@ jest.spyOn(AirnodeRrpV0DryRunFactory, 'connect').mockImplementation( () => ({ estimateGas: { fulfill: estimateAirnodeRrpOverheadMock }, - } as any) + }) as any ); const createAirnodeRrpFake = () => new ethers.Contract('address', ['ABI']) as unknown as AirnodeRrpV0; diff --git a/packages/airnode-node/src/handlers/sign-oev-data.test.ts b/packages/airnode-node/src/handlers/sign-oev-data.test.ts index 858c3aab11..e36828c4ac 100644 --- a/packages/airnode-node/src/handlers/sign-oev-data.test.ts +++ b/packages/airnode-node/src/handlers/sign-oev-data.test.ts @@ -11,9 +11,6 @@ describe('signOevData', () => { beaconId: '0x1032c3cbea7692429f3f1bdb72c47b5c61bdd3ca995a763027f8aa511b42b11b', templateId: '0x64a8f8e70cd1bd4e4621bde25053bf4e22633241effa9f768bf18ff6400dc702', airnodeAddress: '0x9A2Df85E73851e27044504d72563696E5cE86B95', - endpointId: '0xa473a7ca2d5211e6e5766cc6a27c6e90a4f0270f13565e303c56a629815ed60a', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000657468657265756d000000000000000000000000000000000000000000000000', timestamp: '1677747253', encodedValue: '0x0000000000000000000000000000000000000000000000000000000000000064', // 100 signature: @@ -23,9 +20,6 @@ describe('signOevData', () => { beaconId: '0xd6965b1162b263e4dac3084ff0589614a464ac3e4ca012cb90ebb73094f7204e', templateId: '0x306c24b3373f82f267e678464c3bbca29ca5657d0cc6fa4e92981ff91e7c97f3', airnodeAddress: '0x9A2Df85E73851e27044504d72563696E5cE86B95', - endpointId: '0x6c0d51132b51cfca233be8f652189a62d1d9e3d7e0fed3dd2f131ebbf01d31d5', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000626974636f696e00000000000000000000000000000000000000000000000000', timestamp: '1677747310', encodedValue: '0x0000000000000000000000000000000000000000000000000000000000000096', // 150 signature: @@ -35,9 +29,6 @@ describe('signOevData', () => { beaconId: '0xac1054d456689fa9d63e70d6a39b2f3896f494a544865969f1de6d3a61bf10ed', templateId: '0xf13fcbc7e9b814d6f42ca68793c4c5843950d7d77f4c54105669468efc7bb8a0', airnodeAddress: '0xc89216a9adFA290354eB5365C3d5de6B6A24296a', - endpointId: '0x0441ead8bafbca489e41d994bdde04d233b88423d93bd789651f2dd60d11f752', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000646f6765636f696e000000000000000000000000000000000000000000000000', timestamp: '1677747379', encodedValue: '0x00000000000000000000000000000000000000000000000000000000000000c8', // 200 signature: diff --git a/packages/airnode-node/src/workers/local-gateways/index.ts b/packages/airnode-node/src/workers/local-gateways/index.ts index 4d5ffa36ab..3490f2e56d 100644 --- a/packages/airnode-node/src/workers/local-gateways/index.ts +++ b/packages/airnode-node/src/workers/local-gateways/index.ts @@ -1 +1,2 @@ export * from './validation'; +export { DEFAULT_PATH_KEY } from './server'; diff --git a/packages/airnode-node/src/workers/local-gateways/server.ts b/packages/airnode-node/src/workers/local-gateways/server.ts index 8041159831..2a79567a52 100644 --- a/packages/airnode-node/src/workers/local-gateways/server.ts +++ b/packages/airnode-node/src/workers/local-gateways/server.ts @@ -23,7 +23,7 @@ const httpSignedDataBodySchema = z.object({ encodedParameters: z.string(), }); const DEFAULT_PORT = 3000; -const DEFAULT_PATH_KEY = '01234567-abcd-abcd-abcd-012345678abc'; +export const DEFAULT_PATH_KEY = '01234567-abcd-abcd-abcd-012345678abc'; export function getGatewaysUrl(port: number = DEFAULT_PORT, path?: string) { const base = `http://localhost:${port || DEFAULT_PORT}`; diff --git a/packages/airnode-node/src/workers/local-gateways/validation.test.ts b/packages/airnode-node/src/workers/local-gateways/validation.test.ts index 5513a25443..05e4d3da61 100644 --- a/packages/airnode-node/src/workers/local-gateways/validation.test.ts +++ b/packages/airnode-node/src/workers/local-gateways/validation.test.ts @@ -35,9 +35,6 @@ const validDecodedBeacons = [ beaconId: '0x1032c3cbea7692429f3f1bdb72c47b5c61bdd3ca995a763027f8aa511b42b11b', templateId: '0x64a8f8e70cd1bd4e4621bde25053bf4e22633241effa9f768bf18ff6400dc702', airnodeAddress: '0x9A2Df85E73851e27044504d72563696E5cE86B95', - endpointId: '0xa473a7ca2d5211e6e5766cc6a27c6e90a4f0270f13565e303c56a629815ed60a', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000657468657265756d000000000000000000000000000000000000000000000000', signedData: { timestamp: '1677747253', encodedValue: '0x00000000000000000000000000000000000000000000000000000000000003e8', // 1000 @@ -50,9 +47,6 @@ const validDecodedBeacons = [ beaconId: '0xd6965b1162b263e4dac3084ff0589614a464ac3e4ca012cb90ebb73094f7204e', templateId: '0x306c24b3373f82f267e678464c3bbca29ca5657d0cc6fa4e92981ff91e7c97f3', airnodeAddress: '0x9A2Df85E73851e27044504d72563696E5cE86B95', - endpointId: '0x6c0d51132b51cfca233be8f652189a62d1d9e3d7e0fed3dd2f131ebbf01d31d5', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000626974636f696e00000000000000000000000000000000000000000000000000', signedData: { timestamp: '1677747310', encodedValue: '0x00000000000000000000000000000000000000000000000000000000000003e9', // 1001 @@ -65,9 +59,6 @@ const validDecodedBeacons = [ beaconId: '0xac1054d456689fa9d63e70d6a39b2f3896f494a544865969f1de6d3a61bf10ed', templateId: '0xf13fcbc7e9b814d6f42ca68793c4c5843950d7d77f4c54105669468efc7bb8a0', airnodeAddress: '0xc89216a9adFA290354eB5365C3d5de6B6A24296a', - endpointId: '0x0441ead8bafbca489e41d994bdde04d233b88423d93bd789651f2dd60d11f752', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000646f6765636f696e000000000000000000000000000000000000000000000000', signedData: { timestamp: '1677747379', encodedValue: '0x00000000000000000000000000000000000000000000000000000000000003ea', // 1002 @@ -82,12 +73,12 @@ const validBeaconsWithIds = validDecodedBeacons.map>((de ); const validRequestBody: ProcessSignOevDataRequestBody = { chainId: 31337, - dapiServerAddress: '0x720D8B97a6B90AB8a53358447Df5cf28A9391Ab4', + api3ServerV1: '0x720D8B97a6B90AB8a53358447Df5cf28A9391Ab4', oevProxyAddress: '0x9AA42184aFD00c9599CE05748E2199F8f083036b', updateId: '0x3039656530346630306130383438646138323665616363636538343664303000', bidderAddress: '0xb5c062D4d799b85B4e29c274F9570Fd8216AED68', bidAmount: '0x0000000000000000000000000000000000000000000000000000000a571a14c0', - beacons: validBeaconsWithIds.map((beacon) => omit(beacon, ['templateId', 'beaconId'])), + beacons: validBeaconsWithIds.map((beacon) => omit(beacon, ['beaconId'])), }; describe('verifyHttpRequest', () => { @@ -252,10 +243,8 @@ describe('validateBeacons', () => { expect(validateBeacons([validRequestBody.beacons[0]])).toEqual([beacon]); }); - it('returns null if some beacons have invalid encoded parameters', () => { - expect( - validateBeacons([{ ...validRequestBody.beacons[0], encodedParameters: 'invalid encoded parameters' }]) - ).toBeNull(); + it('returns null if some beacons have invalid template IDs', () => { + expect(validateBeacons([{ ...validRequestBody.beacons[0], templateId: 'invalidTemplate' }])).toBeNull(); }); }); @@ -310,7 +299,7 @@ describe('verifySignOevDataRequest', () => { ...validBeaconsWithIds[0], signedData: { ...validBeaconsWithIds[0].signedData, timestamp: '1677740000' }, }; - const invalidEncodedParametersBeacon: BeaconWithIds = { ...validBeaconsWithIds[0], encodedParameters: 'invalid' }; + const invalidTemplateIdBeacon: BeaconWithIds = { ...validBeaconsWithIds[0], templateId: 'invalid' }; const invalidEncodedValueBeacon: BeaconWithIds = { ...validBeaconsWithIds[0], signedData: { ...validBeaconsWithIds[0].signedData, encodedValue: 'invalid' }, @@ -395,10 +384,10 @@ describe('verifySignOevDataRequest', () => { }); }); - it('fails if there are beacons with invalid encoded parameters', () => { + it('fails if there are beacons with invalid template ID', () => { expect( verifySignOevDataRequest({ - beacons: [...validRequestBody.beacons, invalidEncodedParametersBeacon], + beacons: [...validRequestBody.beacons, invalidTemplateIdBeacon], } as ProcessSignOevDataRequestBody) ).toEqual({ success: false, diff --git a/packages/airnode-node/src/workers/local-gateways/validation.ts b/packages/airnode-node/src/workers/local-gateways/validation.ts index 8296ed388e..214f1344fe 100644 --- a/packages/airnode-node/src/workers/local-gateways/validation.ts +++ b/packages/airnode-node/src/workers/local-gateways/validation.ts @@ -6,11 +6,10 @@ import { ethers } from 'ethers'; import { decode } from '@api3/airnode-abi'; import { logger } from '@api3/airnode-utilities'; import { goSync } from '@api3/promise-utils'; -import { ApiCallParameters, ApiCallTemplateWithoutId } from '../../types'; +import { ApiCallParameters } from '../../types'; import { Config, endpointIdSchema } from '../../config'; import { apiCallParametersSchema } from '../../validation'; import { getAirnodeWalletFromPrivateKey } from '../../evm'; -import { getExpectedTemplateIdV1 } from '../../evm/templates'; const TIMESTAMP_DEVIATION = 2; // in minutes // Solidity type(int224).min @@ -121,8 +120,7 @@ export function verifyHttpSignedDataRequest( const beaconSchema = z.object({ airnodeAddress: z.string(), - endpointId: z.string(), - encodedParameters: z.string(), + templateId: z.string(), // Signed data might be missing for some of the beacons (as long as the majority has the data). We still need to know // all of the beacons to derive the data feed ID. signedData: z @@ -146,7 +144,7 @@ export interface BeaconDecoded extends Required { export const signOevDataBodySchema = z.object({ chainId: z.number().positive(), - dapiServerAddress: z.string(), + api3ServerV1: z.string(), oevProxyAddress: z.string(), updateId: z.string(), bidderAddress: z.string(), @@ -234,18 +232,9 @@ export const validateBeacons = (beacons: Beacon[]): BeaconWithIds[] | null => { const goValidateBeacons = goSync(() => { const beaconsWithIds: BeaconWithIds[] = []; for (const beacon of beacons) { - const { airnodeAddress, encodedParameters, endpointId } = beacon; - - // To check parameters validity, exception is caught by the goSync - decode(encodedParameters); - - const template: ApiCallTemplateWithoutId = { - airnodeAddress, - endpointId, - encodedParameters, - }; - // Both template ID and beacon ID can fail, but it's OK because we are wrapping the validation in goSync - const templateId = getExpectedTemplateIdV1(template); + const { airnodeAddress, templateId } = beacon; + + // Beacon ID derivation can fail, but it's OK because we are wrapping the validation in goSync const beaconId = deriveBeaconId(airnodeAddress, templateId); beaconsWithIds.push({ ...beacon, templateId, beaconId }); @@ -262,7 +251,7 @@ export function verifySignOevDataRequest(requestBody: ProcessSignOevDataRequestB oevUpdateHash: string; beacons: BeaconDecoded[]; }> { - const { chainId, dapiServerAddress, oevProxyAddress, updateId, bidderAddress, bidAmount, beacons } = requestBody; + const { chainId, api3ServerV1, oevProxyAddress, updateId, bidderAddress, bidAmount, beacons } = requestBody; const beaconsWithIds = validateBeacons(beacons); if (!beaconsWithIds) { @@ -326,7 +315,7 @@ export function verifySignOevDataRequest(requestBody: ProcessSignOevDataRequestB logger.debug( `Deriving update hash. Params: ${JSON.stringify([ chainId, - dapiServerAddress, + api3ServerV1, oevProxyAddress, dataFeedId, updateId, @@ -340,7 +329,7 @@ export function verifySignOevDataRequest(requestBody: ProcessSignOevDataRequestB ['uint256', 'address', 'address', 'bytes32', 'bytes32', 'uint256', 'bytes', 'address', 'uint256'], [ chainId, - dapiServerAddress, + api3ServerV1, oevProxyAddress, dataFeedId, updateId, diff --git a/packages/airnode-node/test/fixtures/config/config.valid.json b/packages/airnode-node/test/fixtures/config/config.valid.json index d34b88b62b..76d1afc72e 100644 --- a/packages/airnode-node/test/fixtures/config/config.valid.json +++ b/packages/airnode-node/test/fixtures/config/config.valid.json @@ -54,7 +54,7 @@ }, "logFormat": "plain", "logLevel": "INFO", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -84,7 +84,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-node/test/fixtures/config/ois.ts b/packages/airnode-node/test/fixtures/config/ois.ts index b7702eb803..5bc67a9221 100644 --- a/packages/airnode-node/test/fixtures/config/ois.ts +++ b/packages/airnode-node/test/fixtures/config/ois.ts @@ -2,7 +2,7 @@ import { OIS } from '@api3/ois'; export function buildOIS(ois?: Partial): OIS { return { - oisFormat: '2.1.0', + oisFormat: '2.3.1', version: '1.2.3', title: 'Currency Converter API', apiSpecifications: { diff --git a/packages/airnode-operation/CHANGELOG.md b/packages/airnode-operation/CHANGELOG.md index 4e77849689..e549d93e7b 100644 --- a/packages/airnode-operation/CHANGELOG.md +++ b/packages/airnode-operation/CHANGELOG.md @@ -1,5 +1,14 @@ # @api3/airnode-operation +## 0.13.0 + +### Patch Changes + +- Updated dependencies [[`87cee037`](https://github.com/api3dao/airnode/commit/87cee0372afc60acb141ad308d3664172f3cbdb6), [`d2e5a04b`](https://github.com/api3dao/airnode/commit/d2e5a04bf6e88de1888f044dfb171344171ba0ea), [`1d7e4b2f`](https://github.com/api3dao/airnode/commit/1d7e4b2fe4467cee05a6d5f4b34b772d377337df), [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3)]: + - @api3/airnode-protocol@0.13.0 + - @api3/airnode-utilities@0.13.0 + - @api3/airnode-abi@0.13.0 + ## 0.12.0 ### Minor Changes diff --git a/packages/airnode-operation/package.json b/packages/airnode-operation/package.json index 7411f86b9d..6f74bc049c 100644 --- a/packages/airnode-operation/package.json +++ b/packages/airnode-operation/package.json @@ -1,7 +1,7 @@ { "name": "@api3/airnode-operation", "license": "MIT", - "version": "0.12.0", + "version": "0.13.0", "private": false, "main": "dist/index", "types": "dist/index", @@ -28,9 +28,9 @@ "test": "hardhat test" }, "dependencies": { - "@api3/airnode-abi": "^0.12.0", - "@api3/airnode-protocol": "^0.12.0", - "@api3/airnode-utilities": "^0.12.0", + "@api3/airnode-abi": "^0.13.0", + "@api3/airnode-protocol": "^0.13.0", + "@api3/airnode-utilities": "^0.13.0", "ethers": "^5.7.2", "express": "^4.18.2", "hardhat": "^2.14.1", @@ -39,9 +39,9 @@ }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.2.3", - "@types/express": "^4.17.17", - "@types/morgan": "^1.9.4", - "rimraf": "^5.0.1", - "typescript": "^5.1.6" + "@types/express": "^4.17.20", + "@types/morgan": "^1.9.7", + "rimraf": "^5.0.5", + "typescript": "^5.2.2" } } diff --git a/packages/airnode-protocol/CHANGELOG.md b/packages/airnode-protocol/CHANGELOG.md index ab93eab02b..52e6018288 100644 --- a/packages/airnode-protocol/CHANGELOG.md +++ b/packages/airnode-protocol/CHANGELOG.md @@ -1,5 +1,19 @@ # @api3/airnode-protocol +## 0.13.0 + +### Minor Changes + +- [#1864](https://github.com/api3dao/airnode/pull/1864) [`87cee037`](https://github.com/api3dao/airnode/commit/87cee0372afc60acb141ad308d3664172f3cbdb6) Thanks [@Ashar2shahid](https://github.com/Ashar2shahid)! - Deploy protocol contracts to linea,linea-testnet, base,base-testnet, mantle,mantle-testnet, polygon-zkevm,polygon-zkevm-testnet + +### Patch Changes + +- [#1887](https://github.com/api3dao/airnode/pull/1887) [`d2e5a04b`](https://github.com/api3dao/airnode/commit/d2e5a04bf6e88de1888f044dfb171344171ba0ea) Thanks [@dcroote](https://github.com/dcroote)! - Minor README and scripts updates + +- [#1830](https://github.com/api3dao/airnode/pull/1830) [`1d7e4b2f`](https://github.com/api3dao/airnode/commit/1d7e4b2fe4467cee05a6d5f4b34b772d377337df) Thanks [@renovate](https://github.com/apps/renovate)! - Update to @smithy package for aws-sdk + +- [#1825](https://github.com/api3dao/airnode/pull/1825) [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3) Thanks [@renovate](https://github.com/apps/renovate)! - Apply prettier v3 formatting + ## 0.12.0 ### Minor Changes diff --git a/packages/airnode-protocol/README.md b/packages/airnode-protocol/README.md index 63e06e09ae..4f7507839c 100644 --- a/packages/airnode-protocol/README.md +++ b/packages/airnode-protocol/README.md @@ -21,8 +21,13 @@ yarn run test:coverage yarn run test:gas ``` -Deploy the contracts on a network (`` must be one of the names from `credentials.example.json`), verify the -deployment +### Contract deployment + +To deploy the contracts on a network first copy `example.env` to `.env`. Enter a mnemonic and any appropriate API keys. +Note that the mnemonic must be present (though can be arbitrary) even if the exclusive goal is contract verification. +The `` in the below commands must correspond to a filename (without the `.json` extension) from +https://github.com/api3dao/chains/tree/main/chains. If a hardhat error occurs during verification stating that a json +file in `artifacts/build-info` is missing, running `yarn run clean` followed by `yarn run compile` should fix it. ```sh # Deploys deterministically (does not work on some chains) @@ -34,8 +39,14 @@ NETWORK= yarn run deploy:undeterministic # Verifies the deployment on the respective block explorer (not supported for some chains) NETWORK= yarn run deploy:verify -# Verifies the deployment locally (only works for undeterministic deployments) -NETWORK= yarn run deploy:verify-local +# Verifies the deployments locally +yarn run test:verify-local + +# The same as above, but for a specific network +NETWORK= yarn run test:verify-local:network + +# Generates deployments/references.json +yarn run deploy:generate-references ``` ### Deterministic deployment addresses @@ -46,6 +57,8 @@ RequesterAuthorizerWithAirnode: 0xf18c105D0375E80980e4EED829a4A68A539E6178 AccessControlRegistry: 0x92E5125adF385d86beDb950793526106143b6Df1 +AirnodeRrpV0DryRun: 0x2e768206bf5112e7D7efAf1d9df614C26475193f + ### Integration notes - `arbitrum`, `avalanche`, `metis` and their testnets do not support deterministic deployment and are deployed diff --git a/packages/airnode-protocol/deployments/base-goerli-testnet/.chainId b/packages/airnode-protocol/deployments/base-goerli-testnet/.chainId new file mode 100644 index 0000000000..9b24bf0236 --- /dev/null +++ b/packages/airnode-protocol/deployments/base-goerli-testnet/.chainId @@ -0,0 +1 @@ +84531 \ No newline at end of file diff --git a/packages/airnode-protocol/deployments/base-goerli-testnet/AccessControlRegistry.json b/packages/airnode-protocol/deployments/base-goerli-testnet/AccessControlRegistry.json new file mode 100644 index 0000000000..7f0bb03bd9 --- /dev/null +++ b/packages/airnode-protocol/deployments/base-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": "0x389504a3926b12610f70e2898a86fefc02db70b18ff3fcf5cc4213140c1ae0ce", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 1, + "gasUsed": "1006245", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xf5da0d126f21fe67bc21d3a66bcac3e1a32430ed5eaa4a636b31d43709224c69", + "transactionHash": "0x389504a3926b12610f70e2898a86fefc02db70b18ff3fcf5cc4213140c1ae0ce", + "logs": [], + "blockNumber": 8393354, + "cumulativeGasUsed": "1053098", + "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/base-goerli-testnet/AirnodeRrpV0.json b/packages/airnode-protocol/deployments/base-goerli-testnet/AirnodeRrpV0.json new file mode 100644 index 0000000000..223fb4818c --- /dev/null +++ b/packages/airnode-protocol/deployments/base-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": "0xa4c56f95e8fa4b877f9db69ba788714064b26933039005e36c8769e2d10e1101", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 1, + "gasUsed": "2228110", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xc506cc48f46f08719761be79a9a72639dfb1cb08c17eff0a5443d852c09286d6", + "transactionHash": "0xa4c56f95e8fa4b877f9db69ba788714064b26933039005e36c8769e2d10e1101", + "logs": [], + "blockNumber": 8393359, + "cumulativeGasUsed": "2274951", + "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/base-goerli-testnet/AirnodeRrpV0DryRun.json b/packages/airnode-protocol/deployments/base-goerli-testnet/AirnodeRrpV0DryRun.json new file mode 100644 index 0000000000..e5f3eeb963 --- /dev/null +++ b/packages/airnode-protocol/deployments/base-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": "0x22ccdd37e25fbeccbcc6f7676554386177488d6d53ede19898a0ef5be69071de", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 1, + "gasUsed": "582904", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x834f6743a6bfab8a32176eb7cdae0af4a107528fdec5592d8b3aac0e765b78e0", + "transactionHash": "0x22ccdd37e25fbeccbcc6f7676554386177488d6d53ede19898a0ef5be69071de", + "logs": [], + "blockNumber": 8394709, + "cumulativeGasUsed": "629757", + "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/base-goerli-testnet/RequesterAuthorizerWithAirnode.json b/packages/airnode-protocol/deployments/base-goerli-testnet/RequesterAuthorizerWithAirnode.json new file mode 100644 index 0000000000..82816cc70a --- /dev/null +++ b/packages/airnode-protocol/deployments/base-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": "0x09477ede476e884f55f6689c62037a61cec91f58bf8fdc2378d25d16fb83db20", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 1, + "gasUsed": "1570550", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x377b0226bf3e11e4977e4618267aceec3776e1a340df016df7f295b59091b412", + "transactionHash": "0x09477ede476e884f55f6689c62037a61cec91f58bf8fdc2378d25d16fb83db20", + "logs": [], + "blockNumber": 8393357, + "cumulativeGasUsed": "1620979", + "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/boba-avalanche/solcInputs/0ab40609a497e05bef785ddb4724b7a0.json b/packages/airnode-protocol/deployments/base-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json similarity index 95% rename from packages/airnode-protocol/deployments/boba-avalanche/solcInputs/0ab40609a497e05bef785ddb4724b7a0.json rename to packages/airnode-protocol/deployments/base-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json index 4102a36a2a..d38c4a14fa 100644 --- a/packages/airnode-protocol/deployments/boba-avalanche/solcInputs/0ab40609a497e05bef785ddb4724b7a0.json +++ b/packages/airnode-protocol/deployments/base-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json @@ -1,32 +1,23 @@ { "language": "Solidity", "sources": { - "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" - }, - "@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/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" }, - "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" + "@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" }, - "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" + "@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/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/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/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" + "@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" @@ -34,125 +25,140 @@ "@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" }, - "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/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/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" + "@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" }, - "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" + "@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/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/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/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/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/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" + "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/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/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/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/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/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/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/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/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/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/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" }, - "@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" + "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/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/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" }, - "@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" + "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/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/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/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/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 (address airnode, bytes32 endpointId, bytes memory parameters);\n}\n" + "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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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": { diff --git a/packages/airnode-protocol/deployments/base/.chainId b/packages/airnode-protocol/deployments/base/.chainId new file mode 100644 index 0000000000..2a0c26389c --- /dev/null +++ b/packages/airnode-protocol/deployments/base/.chainId @@ -0,0 +1 @@ +8453 \ No newline at end of file diff --git a/packages/airnode-protocol/deployments/base/AccessControlRegistry.json b/packages/airnode-protocol/deployments/base/AccessControlRegistry.json new file mode 100644 index 0000000000..4ba633686a --- /dev/null +++ b/packages/airnode-protocol/deployments/base/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": "0xf9b4504259a698975d2b9491d25804be88e5c980231a5172b352e3a833dc1cd0", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 10, + "gasUsed": "1006245", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xe63caef8a0817e38a7a1a7ce7d142c8876d6aabdb786333bebea50450e6d81d6", + "transactionHash": "0xf9b4504259a698975d2b9491d25804be88e5c980231a5172b352e3a833dc1cd0", + "logs": [], + "blockNumber": 2585534, + "cumulativeGasUsed": "3389905", + "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/base/AirnodeRrpV0.json b/packages/airnode-protocol/deployments/base/AirnodeRrpV0.json new file mode 100644 index 0000000000..8973b0c751 --- /dev/null +++ b/packages/airnode-protocol/deployments/base/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": "0x359ac9edcaf938d97d09ac7589f3b7acbe864be1def10d98ec1cceda7e1ac272", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 14, + "gasUsed": "2228110", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x4c95812b34ab1728e4fa4ce614054f829f2a167ef474807cc93866997ee74fac", + "transactionHash": "0x359ac9edcaf938d97d09ac7589f3b7acbe864be1def10d98ec1cceda7e1ac272", + "logs": [], + "blockNumber": 2585539, + "cumulativeGasUsed": "4320291", + "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/base/AirnodeRrpV0DryRun.json b/packages/airnode-protocol/deployments/base/AirnodeRrpV0DryRun.json new file mode 100644 index 0000000000..c7c979318e --- /dev/null +++ b/packages/airnode-protocol/deployments/base/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": "0x3ea5da23d56225bb3fdf214099080981fc6bb8840b2f1ec4db1bf95dac1a590c", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 5, + "gasUsed": "582904", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x59dcb895ae6bf8914d64910ebd32f66215631e2b186c5972566b53ed4e8d198a", + "transactionHash": "0x3ea5da23d56225bb3fdf214099080981fc6bb8840b2f1ec4db1bf95dac1a590c", + "logs": [], + "blockNumber": 2585542, + "cumulativeGasUsed": "948821", + "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/base/RequesterAuthorizerWithAirnode.json b/packages/airnode-protocol/deployments/base/RequesterAuthorizerWithAirnode.json new file mode 100644 index 0000000000..22d5f8a6f2 --- /dev/null +++ b/packages/airnode-protocol/deployments/base/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": "0x0e07ae0e0c92fda513eae32a006d59c3f42e8bacdbf31a6d7c13460c31cb3651", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 10, + "gasUsed": "1570550", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x3f2b0610b55139cda4f17c6a3222123c09a627669133a01bf701102a0fa50cb6", + "transactionHash": "0x0e07ae0e0c92fda513eae32a006d59c3f42e8bacdbf31a6d7c13460c31cb3651", + "logs": [], + "blockNumber": 2585537, + "cumulativeGasUsed": "3254389", + "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/boba-avalanche/solcInputs/91bdad71ba8d8c57da42984f65eb24cc.json b/packages/airnode-protocol/deployments/base/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json similarity index 82% rename from packages/airnode-protocol/deployments/boba-avalanche/solcInputs/91bdad71ba8d8c57da42984f65eb24cc.json rename to packages/airnode-protocol/deployments/base/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json index 6418e5d88f..d38c4a14fa 100644 --- a/packages/airnode-protocol/deployments/boba-avalanche/solcInputs/91bdad71ba8d8c57da42984f65eb24cc.json +++ b/packages/airnode-protocol/deployments/base/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json @@ -1,32 +1,23 @@ { "language": "Solidity", "sources": { - "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" - }, - "@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/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" }, - "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" + "@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" }, - "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" + "@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/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/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/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" + "@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" @@ -34,164 +25,140 @@ "@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" }, - "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/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/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" + "@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" }, - "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" + "@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/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/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/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/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/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" - }, - "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/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/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/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/dev/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/dev/access-control-registry/RoleDeriver.sol": { + "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/dev/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/dev/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/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/dev/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/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/dev/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/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" }, - "@openzeppelin/contracts/token/ERC721/IERC721.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\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" }, - "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\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" }, - "@openzeppelin/contracts/token/ERC721/ERC721.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721.sol\";\nimport \"./IERC721Receiver.sol\";\nimport \"./extensions/IERC721Metadata.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Strings.sol\";\nimport \"../../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721 is Context, ERC165, IERC721, IERC721Metadata {\n using Address for address;\n using Strings for uint256;\n\n // Token name\n string private _name;\n\n // Token symbol\n string private _symbol;\n\n // Mapping from token ID to owner address\n mapping(uint256 => address) private _owners;\n\n // Mapping owner address to token count\n mapping(address => uint256) private _balances;\n\n // Mapping from token ID to approved address\n mapping(uint256 => address) private _tokenApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n /**\n * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n interfaceId == type(IERC721).interfaceId ||\n interfaceId == type(IERC721Metadata).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev See {IERC721-balanceOf}.\n */\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ERC721: balance query for the zero address\");\n return _balances[owner];\n }\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n address owner = _owners[tokenId];\n require(owner != address(0), \"ERC721: owner query for nonexistent token\");\n return owner;\n }\n\n /**\n * @dev See {IERC721Metadata-name}.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC721Metadata-symbol}.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n require(_exists(tokenId), \"ERC721Metadata: URI query for nonexistent token\");\n\n string memory baseURI = _baseURI();\n return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n }\n\n /**\n * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n * by default, can be overriden in child contracts.\n */\n function _baseURI() internal view virtual returns (string memory) {\n return \"\";\n }\n\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) public virtual override {\n address owner = ERC721.ownerOf(tokenId);\n require(to != owner, \"ERC721: approval to current owner\");\n\n require(\n _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n \"ERC721: approve caller is not owner nor approved for all\"\n );\n\n _approve(to, tokenId);\n }\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) public view virtual override returns (address) {\n require(_exists(tokenId), \"ERC721: approved query for nonexistent token\");\n\n return _tokenApprovals[tokenId];\n }\n\n /**\n * @dev See {IERC721-setApprovalForAll}.\n */\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _setApprovalForAll(_msgSender(), operator, approved);\n }\n\n /**\n * @dev See {IERC721-isApprovedForAll}.\n */\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _operatorApprovals[owner][operator];\n }\n\n /**\n * @dev See {IERC721-transferFrom}.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n\n _transfer(from, to, tokenId);\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n safeTransferFrom(from, to, tokenId, \"\");\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) public virtual override {\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n _safeTransfer(from, to, tokenId, _data);\n }\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * `_data` is additional data, it has no specified format and it is sent in call to `to`.\n *\n * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n * implement alternative mechanisms to perform token transfer, such as signature-based.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeTransfer(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _transfer(from, to, tokenId);\n require(_checkOnERC721Received(from, to, tokenId, _data), \"ERC721: transfer to non ERC721Receiver implementer\");\n }\n\n /**\n * @dev Returns whether `tokenId` exists.\n *\n * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n *\n * Tokens start existing when they are minted (`_mint`),\n * and stop existing when they are burned (`_burn`).\n */\n function _exists(uint256 tokenId) internal view virtual returns (bool) {\n return _owners[tokenId] != address(0);\n }\n\n /**\n * @dev Returns whether `spender` is allowed to manage `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n require(_exists(tokenId), \"ERC721: operator query for nonexistent token\");\n address owner = ERC721.ownerOf(tokenId);\n return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));\n }\n\n /**\n * @dev Safely mints `tokenId` and transfers it to `to`.\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeMint(address to, uint256 tokenId) internal virtual {\n _safeMint(to, tokenId, \"\");\n }\n\n /**\n * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n */\n function _safeMint(\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _mint(to, tokenId);\n require(\n _checkOnERC721Received(address(0), to, tokenId, _data),\n \"ERC721: transfer to non ERC721Receiver implementer\"\n );\n }\n\n /**\n * @dev Mints `tokenId` and transfers it to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - `to` cannot be the zero address.\n *\n * Emits a {Transfer} event.\n */\n function _mint(address to, uint256 tokenId) internal virtual {\n require(to != address(0), \"ERC721: mint to the zero address\");\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n _beforeTokenTransfer(address(0), to, tokenId);\n\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(address(0), to, tokenId);\n }\n\n /**\n * @dev Destroys `tokenId`.\n * The approval is cleared when the token is burned.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n *\n * Emits a {Transfer} event.\n */\n function _burn(uint256 tokenId) internal virtual {\n address owner = ERC721.ownerOf(tokenId);\n\n _beforeTokenTransfer(owner, address(0), tokenId);\n\n // Clear approvals\n _approve(address(0), tokenId);\n\n _balances[owner] -= 1;\n delete _owners[tokenId];\n\n emit Transfer(owner, address(0), tokenId);\n }\n\n /**\n * @dev Transfers `tokenId` from `from` to `to`.\n * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n *\n * Emits a {Transfer} event.\n */\n function _transfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {\n require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer of token that is not own\");\n require(to != address(0), \"ERC721: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, tokenId);\n\n // Clear approvals from the previous owner\n _approve(address(0), tokenId);\n\n _balances[from] -= 1;\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(from, to, tokenId);\n }\n\n /**\n * @dev Approve `to` to operate on `tokenId`\n *\n * Emits a {Approval} event.\n */\n function _approve(address to, uint256 tokenId) internal virtual {\n _tokenApprovals[tokenId] = to;\n emit Approval(ERC721.ownerOf(tokenId), to, tokenId);\n }\n\n /**\n * @dev Approve `operator` to operate on all of `owner` tokens\n *\n * Emits a {ApprovalForAll} event.\n */\n function _setApprovalForAll(\n address owner,\n address operator,\n bool approved\n ) internal virtual {\n require(owner != operator, \"ERC721: approve to caller\");\n _operatorApprovals[owner][operator] = approved;\n emit ApprovalForAll(owner, operator, approved);\n }\n\n /**\n * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n * The call is not executed if the target address is not a contract.\n *\n * @param from address representing the previous owner of the given token ID\n * @param to target address that will receive the tokens\n * @param tokenId uint256 ID of the token to be transferred\n * @param _data bytes optional data to send along with the call\n * @return bool whether the call correctly returned the expected magic value\n */\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {\n return retval == IERC721Receiver.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n } else {\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes minting\n * and burning.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be\n * transferred to `to`.\n * - When `from` is zero, `tokenId` will be minted for `to`.\n * - When `to` is zero, ``from``'s `tokenId` will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\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" }, - "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\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" }, - "@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" + "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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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" }, - "@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" + "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/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/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/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/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" }, - "@openzeppelin/contracts/metatx/ERC2771Context.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (metatx/ERC2771Context.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Context variant with ERC2771 support.\n */\nabstract contract ERC2771Context is Context {\n address private _trustedForwarder;\n\n constructor(address trustedForwarder) {\n _trustedForwarder = trustedForwarder;\n }\n\n function isTrustedForwarder(address forwarder) public view virtual returns (bool) {\n return forwarder == _trustedForwarder;\n }\n\n function _msgSender() internal view virtual override returns (address sender) {\n if (isTrustedForwarder(msg.sender)) {\n // The assembly code is more direct than the Solidity version using `abi.decode`.\n assembly {\n sender := shr(96, calldataload(sub(calldatasize(), 20)))\n }\n } else {\n return super._msgSender();\n }\n }\n\n function _msgData() internal view virtual override returns (bytes calldata) {\n if (isTrustedForwarder(msg.sender)) {\n return msg.data[:msg.data.length - 20];\n } else {\n return super._msgData();\n }\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/dev/interfaces/IRequesterAuthorizerWithErc721.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\nimport \"../access-control-registry/interfaces/IAccessControlRegistryAdminned.sol\";\n\ninterface IRequesterAuthorizerWithErc721 is\n IERC721Receiver,\n IAccessControlRegistryAdminned\n{\n event SetWithdrawalLeadTime(\n address indexed airnode,\n uint32 withdrawalLeadTime,\n address sender\n );\n\n event SetRequesterBlockStatus(\n address indexed airnode,\n address indexed requester,\n uint256 chainId,\n bool status,\n address sender\n );\n\n event DepositedToken(\n address indexed airnode,\n address indexed requester,\n address indexed depositor,\n uint256 chainId,\n address token,\n uint256 tokenId,\n uint256 tokenDepositCount\n );\n\n event UpdatedDepositRequesterFrom(\n address indexed airnode,\n address indexed requester,\n address indexed depositor,\n uint256 chainId,\n address token,\n uint256 tokenId,\n uint256 tokenDepositCount\n );\n\n event UpdatedDepositRequesterTo(\n address indexed airnode,\n address indexed requester,\n address indexed depositor,\n uint256 chainId,\n address token,\n uint256 tokenId,\n uint256 tokenDepositCount\n );\n\n event InitiatedTokenWithdrawal(\n address indexed airnode,\n address indexed requester,\n address indexed depositor,\n uint256 chainId,\n address token,\n uint256 tokenId,\n uint32 earliestWithdrawalTime,\n uint256 tokenDepositCount\n );\n\n event WithdrewToken(\n address indexed airnode,\n address indexed requester,\n address indexed depositor,\n uint256 chainId,\n address token,\n uint256 tokenId,\n uint256 tokenDepositCount\n );\n\n event RevokedToken(\n address indexed airnode,\n address indexed requester,\n address indexed depositor,\n uint256 chainId,\n address token,\n uint256 tokenId,\n uint256 tokenDepositCount\n );\n\n function setWithdrawalLeadTime(\n address airnode,\n uint32 withdrawalLeadTime\n ) external;\n\n function setRequesterBlockStatus(\n address airnode,\n uint256 chainId,\n address requester,\n bool status\n ) external;\n\n function updateDepositRequester(\n address airnode,\n uint256 chainIdPrevious,\n address requesterPrevious,\n uint256 chainIdNext,\n address requesterNext,\n address token\n ) external;\n\n function initiateTokenWithdrawal(\n address airnode,\n uint256 chainId,\n address requester,\n address token\n ) external returns (uint32 earliestWithdrawalTime);\n\n function withdrawToken(\n address airnode,\n uint256 chainId,\n address requester,\n address token\n ) external;\n\n function revokeToken(\n address airnode,\n uint256 chainId,\n address requester,\n address token,\n address depositor\n ) external;\n\n function airnodeToChainIdToRequesterToTokenToDepositorToDeposit(\n address airnode,\n uint256 chainId,\n address requester,\n address token,\n address depositor\n )\n external\n view\n returns (\n uint256 tokenId,\n uint32 withdrawalLeadTime,\n uint32 earliestWithdrawalTime\n );\n\n function isAuthorized(\n address airnode,\n uint256 chainId,\n address requester,\n address token\n ) external view returns (bool);\n\n function deriveWithdrawalLeadTimeSetterRole(\n address airnode\n ) external view returns (bytes32 withdrawalLeadTimeSetterRole);\n\n function deriveRequesterBlockerRole(\n address airnode\n ) external view returns (bytes32 requesterBlockerRole);\n\n // solhint-disable-next-line func-name-mixedcase\n function WITHDRAWAL_LEAD_TIME_SETTER_ROLE_DESCRIPTION()\n external\n view\n returns (string memory);\n\n // solhint-disable-next-line func-name-mixedcase\n function REQUESTER_BLOCKER_ROLE_DESCRIPTION()\n external\n view\n returns (string memory);\n\n function airnodeToChainIdToRequesterToTokenAddressToTokenDeposits(\n address airnode,\n uint256 chainId,\n address requester,\n address token\n ) external view returns (uint256 tokenDepositCount);\n\n function airnodeToWithdrawalLeadTime(\n address airnode\n ) external view returns (uint32 withdrawalLeadTime);\n\n function airnodeToChainIdToRequesterToBlockStatus(\n address airnode,\n uint256 chainId,\n address requester\n ) external view returns (bool isBlocked);\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": { diff --git a/packages/airnode-protocol/deployments/boba-avalanche/.chainId b/packages/airnode-protocol/deployments/boba-avalanche/.chainId deleted file mode 100644 index 2eee704cdb..0000000000 --- a/packages/airnode-protocol/deployments/boba-avalanche/.chainId +++ /dev/null @@ -1 +0,0 @@ -43288 \ No newline at end of file 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/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/linea-goerli-testnet/.chainId b/packages/airnode-protocol/deployments/linea-goerli-testnet/.chainId new file mode 100644 index 0000000000..14d92a425d --- /dev/null +++ b/packages/airnode-protocol/deployments/linea-goerli-testnet/.chainId @@ -0,0 +1 @@ +59140 \ No newline at end of file diff --git a/packages/airnode-protocol/deployments/linea-goerli-testnet/AccessControlRegistry.json b/packages/airnode-protocol/deployments/linea-goerli-testnet/AccessControlRegistry.json new file mode 100644 index 0000000000..0aa5e4103d --- /dev/null +++ b/packages/airnode-protocol/deployments/linea-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": "0x12eede4f19bd8d810efe3a0fff378cef14546a7e81646f8fbb5df05d262f307d", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 13, + "gasUsed": "1006245", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xb7f73ba7f78756d3b49db5e739fea3f899160841c70c1447dafd7bee3e1a75a0", + "transactionHash": "0x12eede4f19bd8d810efe3a0fff378cef14546a7e81646f8fbb5df05d262f307d", + "logs": [], + "blockNumber": 1335722, + "cumulativeGasUsed": "1304703", + "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/linea-goerli-testnet/AirnodeRrpV0.json b/packages/airnode-protocol/deployments/linea-goerli-testnet/AirnodeRrpV0.json new file mode 100644 index 0000000000..38e69e8866 --- /dev/null +++ b/packages/airnode-protocol/deployments/linea-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": "0x2d9320eab9877e6afaf9f472840f8580f6c911066f3b899c5e6dea445e13c9e4", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 6, + "gasUsed": "2228110", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x3dbe665cdc0255837d090538a8b40a88d3caf4bc6c4a330d46529220a7b2f286", + "transactionHash": "0x2d9320eab9877e6afaf9f472840f8580f6c911066f3b899c5e6dea445e13c9e4", + "logs": [], + "blockNumber": 1335724, + "cumulativeGasUsed": "3429592", + "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/linea-goerli-testnet/AirnodeRrpV0DryRun.json b/packages/airnode-protocol/deployments/linea-goerli-testnet/AirnodeRrpV0DryRun.json new file mode 100644 index 0000000000..57ac84ed75 --- /dev/null +++ b/packages/airnode-protocol/deployments/linea-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": "0x16337b9f1dff5742c81af3c6622e2645cc2097dff66777d12791aa77a0b9fb98", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 9, + "gasUsed": "582904", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x3bf7acecba25bbc05beb2dfc8f095dbf1034adac88a605568c9b3d6d18f24280", + "transactionHash": "0x16337b9f1dff5742c81af3c6622e2645cc2097dff66777d12791aa77a0b9fb98", + "logs": [], + "blockNumber": 1335725, + "cumulativeGasUsed": "2708139", + "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/linea-goerli-testnet/RequesterAuthorizerWithAirnode.json b/packages/airnode-protocol/deployments/linea-goerli-testnet/RequesterAuthorizerWithAirnode.json new file mode 100644 index 0000000000..1a2d7d1d41 --- /dev/null +++ b/packages/airnode-protocol/deployments/linea-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": "0x99ebcc5661d1f5786454d6ae2b8ce286d631682fd9065fe28aeb73d9bebada95", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 8, + "gasUsed": "1570550", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xcdfd1d650bb277d4e5b250e7454a7cca0b4ff5539ab0e1de3a32dc0439b99374", + "transactionHash": "0x99ebcc5661d1f5786454d6ae2b8ce286d631682fd9065fe28aeb73d9bebada95", + "logs": [], + "blockNumber": 1335723, + "cumulativeGasUsed": "1765243", + "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/linea-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json b/packages/airnode-protocol/deployments/linea-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json new file mode 100644 index 0000000000..d38c4a14fa --- /dev/null +++ b/packages/airnode-protocol/deployments/linea-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/linea/.chainId b/packages/airnode-protocol/deployments/linea/.chainId new file mode 100644 index 0000000000..c9e6af42c1 --- /dev/null +++ b/packages/airnode-protocol/deployments/linea/.chainId @@ -0,0 +1 @@ +59144 \ No newline at end of file diff --git a/packages/airnode-protocol/deployments/linea/AccessControlRegistry.json b/packages/airnode-protocol/deployments/linea/AccessControlRegistry.json new file mode 100644 index 0000000000..46b438c4fa --- /dev/null +++ b/packages/airnode-protocol/deployments/linea/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": "0x294ce9a2020270f8fbae8c66144a976b3f7242aa8f4e3ab8f278afc848f5beae", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 3, + "gasUsed": "1006245", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x89a61c454d235ae52229088daafacf4e1c8951e1ae8ad1ce3d4facc3ba67991e", + "transactionHash": "0x294ce9a2020270f8fbae8c66144a976b3f7242aa8f4e3ab8f278afc848f5beae", + "logs": [], + "blockNumber": 190248, + "cumulativeGasUsed": "1304539", + "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/linea/AirnodeRrpV0.json b/packages/airnode-protocol/deployments/linea/AirnodeRrpV0.json new file mode 100644 index 0000000000..b7817c11d9 --- /dev/null +++ b/packages/airnode-protocol/deployments/linea/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": "0xb79388cf9d44570b2b9b34827b17f1478dfe26c15e55859df05267a1d0541d1e", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 8, + "gasUsed": "2228110", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x22a97debd7b9fc5826ce3377aecd3ec42f98c34d7e6fa387e1131534660e1bc1", + "transactionHash": "0xb79388cf9d44570b2b9b34827b17f1478dfe26c15e55859df05267a1d0541d1e", + "logs": [], + "blockNumber": 190250, + "cumulativeGasUsed": "3207960", + "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/linea/AirnodeRrpV0DryRun.json b/packages/airnode-protocol/deployments/linea/AirnodeRrpV0DryRun.json new file mode 100644 index 0000000000..765ba6380c --- /dev/null +++ b/packages/airnode-protocol/deployments/linea/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": "0x8e6295e87493ea7e30bed0c2c2dc0975ed50bec6ca3aa65f8bc290187727688d", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 20, + "gasUsed": "582904", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x331bec9f952a78cbcc2a1ef1db7ca508a5c44da578ad3d18160522bf09d7f441", + "transactionHash": "0x8e6295e87493ea7e30bed0c2c2dc0975ed50bec6ca3aa65f8bc290187727688d", + "logs": [], + "blockNumber": 190251, + "cumulativeGasUsed": "2359112", + "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/linea/RequesterAuthorizerWithAirnode.json b/packages/airnode-protocol/deployments/linea/RequesterAuthorizerWithAirnode.json new file mode 100644 index 0000000000..cf5b8569a3 --- /dev/null +++ b/packages/airnode-protocol/deployments/linea/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": "0x260117c55effd83c5a537157a4022bc30a3564d6f1e166cd24ac469727020305", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 6, + "gasUsed": "1570550", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xece0632e6dd98d771ce2aa219ccb54709a4ea24c081c813e3e7dbef42654f69b", + "transactionHash": "0x260117c55effd83c5a537157a4022bc30a3564d6f1e166cd24ac469727020305", + "logs": [], + "blockNumber": 190249, + "cumulativeGasUsed": "2092345", + "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/linea/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json b/packages/airnode-protocol/deployments/linea/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json new file mode 100644 index 0000000000..d38c4a14fa --- /dev/null +++ b/packages/airnode-protocol/deployments/linea/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/mantle-goerli-testnet/.chainId b/packages/airnode-protocol/deployments/mantle-goerli-testnet/.chainId new file mode 100644 index 0000000000..b30c5d8863 --- /dev/null +++ b/packages/airnode-protocol/deployments/mantle-goerli-testnet/.chainId @@ -0,0 +1 @@ +5001 \ No newline at end of file diff --git a/packages/airnode-protocol/deployments/mantle-goerli-testnet/AccessControlRegistry.json b/packages/airnode-protocol/deployments/mantle-goerli-testnet/AccessControlRegistry.json new file mode 100644 index 0000000000..39ff169d13 --- /dev/null +++ b/packages/airnode-protocol/deployments/mantle-goerli-testnet/AccessControlRegistry.json @@ -0,0 +1,535 @@ +{ + "address": "0xD223DfDCb888CA1539bb3459a83c543A1608F038", + "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": "0xa50bcd9d0d23b1d5112e0b9c0a78b54cfea577440f06693ddc019a07ce85fd1c", + "receipt": { + "to": null, + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": "0xD223DfDCb888CA1539bb3459a83c543A1608F038", + "transactionIndex": 0, + "gasUsed": "1004318", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x0a4974d04275b37825c1609eeef91a73b6c29cd3b7bf38d6010b66e645344180", + "transactionHash": "0xa50bcd9d0d23b1d5112e0b9c0a78b54cfea577440f06693ddc019a07ce85fd1c", + "logs": [], + "blockNumber": 17545702, + "cumulativeGasUsed": "1004318", + "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/mantle-goerli-testnet/AirnodeRrpV0.json b/packages/airnode-protocol/deployments/mantle-goerli-testnet/AirnodeRrpV0.json new file mode 100644 index 0000000000..563fd789c6 --- /dev/null +++ b/packages/airnode-protocol/deployments/mantle-goerli-testnet/AirnodeRrpV0.json @@ -0,0 +1,1184 @@ +{ + "address": "0x20C9e9610d4e719a39F82893b3f42e2730F42778", + "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": "0x77d1bfed9c6c7ea50568edcb31acc3cebc497fce4b4e872e95d2a0f530295a61", + "receipt": { + "to": null, + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": "0x20C9e9610d4e719a39F82893b3f42e2730F42778", + "transactionIndex": 0, + "gasUsed": "2223914", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xadba7a681e4d1a0427143ccea31540152c55a63941b2cd771a2055fc0d4eeab6", + "transactionHash": "0x77d1bfed9c6c7ea50568edcb31acc3cebc497fce4b4e872e95d2a0f530295a61", + "logs": [], + "blockNumber": 17545708, + "cumulativeGasUsed": "2223914", + "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/mantle-goerli-testnet/AirnodeRrpV0DryRun.json b/packages/airnode-protocol/deployments/mantle-goerli-testnet/AirnodeRrpV0DryRun.json new file mode 100644 index 0000000000..f9c9753153 --- /dev/null +++ b/packages/airnode-protocol/deployments/mantle-goerli-testnet/AirnodeRrpV0DryRun.json @@ -0,0 +1,163 @@ +{ + "address": "0x3e10e6eF3c602885a9Cafd9785BD2143c52fbFF1", + "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": "0x3314978f431bf09ba0930cb901df665837f89e3d803575bab35d31200fa3f97e", + "receipt": { + "to": null, + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": "0x3e10e6eF3c602885a9Cafd9785BD2143c52fbFF1", + "transactionIndex": 0, + "gasUsed": "581748", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x4c4ba0e767537a26d0add132e67e8b9d8d8697c5a8172397e8dac880101797fb", + "transactionHash": "0x3314978f431bf09ba0930cb901df665837f89e3d803575bab35d31200fa3f97e", + "logs": [], + "blockNumber": 17545715, + "cumulativeGasUsed": "581748", + "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/mantle-goerli-testnet/RequesterAuthorizerWithAirnode.json b/packages/airnode-protocol/deployments/mantle-goerli-testnet/RequesterAuthorizerWithAirnode.json new file mode 100644 index 0000000000..67c53c9602 --- /dev/null +++ b/packages/airnode-protocol/deployments/mantle-goerli-testnet/RequesterAuthorizerWithAirnode.json @@ -0,0 +1,912 @@ +{ + "address": "0x4A0b644219d07fEa25B701AAf89b963576b468dC", + "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": "0x06cf98eb33f80b6eb7df541dcbf557ff31035f3bd4123e7f4781058a53b0a039", + "receipt": { + "to": null, + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": "0x4A0b644219d07fEa25B701AAf89b963576b468dC", + "transactionIndex": 0, + "gasUsed": "1567323", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x5bf0994fac3a80c433038b645b1525a09705c32fcdb88df9ecc22c20a27367c8", + "transactionHash": "0x06cf98eb33f80b6eb7df541dcbf557ff31035f3bd4123e7f4781058a53b0a039", + "logs": [], + "blockNumber": 17545705, + "cumulativeGasUsed": "1567323", + "status": 1, + "byzantium": true + }, + "args": ["0xD223DfDCb888CA1539bb3459a83c543A1608F038", "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/mantle-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json b/packages/airnode-protocol/deployments/mantle-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json new file mode 100644 index 0000000000..d38c4a14fa --- /dev/null +++ b/packages/airnode-protocol/deployments/mantle-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/mantle/.chainId b/packages/airnode-protocol/deployments/mantle/.chainId new file mode 100644 index 0000000000..0b3e0a69a8 --- /dev/null +++ b/packages/airnode-protocol/deployments/mantle/.chainId @@ -0,0 +1 @@ +5000 \ No newline at end of file diff --git a/packages/airnode-protocol/deployments/boba-avalanche/AccessControlRegistry.json b/packages/airnode-protocol/deployments/mantle/AccessControlRegistry.json similarity index 99% rename from packages/airnode-protocol/deployments/boba-avalanche/AccessControlRegistry.json rename to packages/airnode-protocol/deployments/mantle/AccessControlRegistry.json index e05a4cd174..5628b764aa 100644 --- a/packages/airnode-protocol/deployments/boba-avalanche/AccessControlRegistry.json +++ b/packages/airnode-protocol/deployments/mantle/AccessControlRegistry.json @@ -355,25 +355,25 @@ "type": "function" } ], - "transactionHash": "0x6a26abf605bd9966261bfa38d0798267d1f8debc6ddc146bbf33a8bd1fb952d1", + "transactionHash": "0x37b71a2378c6bf27d0fd6475e63662f8a21f3fef0c426366cca5331f8b6113fd", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", "contractAddress": null, "transactionIndex": 0, - "gasUsed": "1110952", + "gasUsed": "1006245", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xec74aae78bc7ab16b9402b737b59cb5fde19206f56777895913c6027a96884d0", - "transactionHash": "0x6a26abf605bd9966261bfa38d0798267d1f8debc6ddc146bbf33a8bd1fb952d1", + "blockHash": "0xa928009eae67676fbd2702d10f65d33e2c50ff5e7a36b03d317f72c70e981d6e", + "transactionHash": "0x37b71a2378c6bf27d0fd6475e63662f8a21f3fef0c426366cca5331f8b6113fd", "logs": [], - "blockNumber": 29167, - "cumulativeGasUsed": "1110952", + "blockNumber": 1803720, + "cumulativeGasUsed": "1006245", "status": 1, "byzantium": true }, "args": [], "numDeployments": 1, - "solcInputHash": "0ab40609a497e05bef785ddb4724b7a0", + "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", diff --git a/packages/airnode-protocol/deployments/boba-avalanche/AirnodeRrpV0.json b/packages/airnode-protocol/deployments/mantle/AirnodeRrpV0.json similarity index 98% rename from packages/airnode-protocol/deployments/boba-avalanche/AirnodeRrpV0.json rename to packages/airnode-protocol/deployments/mantle/AirnodeRrpV0.json index 34b4821662..1800c1bf31 100644 --- a/packages/airnode-protocol/deployments/boba-avalanche/AirnodeRrpV0.json +++ b/packages/airnode-protocol/deployments/mantle/AirnodeRrpV0.json @@ -1,5 +1,5 @@ { - "address": "0xd864A45334C7a632cA9149993682354D7f967F28", + "address": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "abi": [ { "anonymous": false, @@ -812,28 +812,28 @@ "type": "function" } ], - "transactionHash": "0xa6871bb26dfbeae3d9f4aa60bb92730370d1fd5f429069ee74088e9b44a9ee61", + "transactionHash": "0x8ee6c630eef2a9a75c41c32af6c9b052836e740c0d1542d05cb740f5a8a69769", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", "contractAddress": null, "transactionIndex": 0, - "gasUsed": "2400605", + "gasUsed": "2228110", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x57a66ad9ea820b12ab96f6e78db26c8b0b7c8d36dee27b71df1e718bee65e0ff", - "transactionHash": "0xa6871bb26dfbeae3d9f4aa60bb92730370d1fd5f429069ee74088e9b44a9ee61", + "blockHash": "0xff487b10b6a3f6e6874578ff6c838d91e8c054192133875f53bdc6081ee29a0c", + "transactionHash": "0x8ee6c630eef2a9a75c41c32af6c9b052836e740c0d1542d05cb740f5a8a69769", "logs": [], - "blockNumber": 29169, - "cumulativeGasUsed": "2400605", + "blockNumber": 1803734, + "cumulativeGasUsed": "2228110", "status": 1, "byzantium": true }, "args": [], "numDeployments": 1, - "solcInputHash": "0ab40609a497e05bef785ddb4724b7a0", - "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 (address airnode, bytes32 endpointId, bytes memory parameters);\\n}\\n\",\"keccak256\":\"0x6ea33e425495a9e12050fd7f24662e15e08ef347411f6ad34622a3daeb36f68e\",\"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": "0x608060405234801561001057600080fd5b5061274d806100206000396000f3fe6080604052600436106100f35760003560e01c806376428c9b1161008a578063acbe180011610059578063acbe1800146102f7578063addf027c14610317578063ca31d58614610337578063f8fa73a11461036457600080fd5b806376428c9b146102405780637e7166f31461026f5780638a33be011461029c578063a81e9f79146102bc57600080fd5b80633c7fe5e3116100c65780633c7fe5e3146101ae57806350743bb9146101c157806352e41f99146102005780636e6be03f1461022057600080fd5b80630a631576146100f85780631d414cbd146101305780631decbf181461015257806332393f2b14610180575b600080fd5b34801561010457600080fd5b50610118610113366004611bd0565b610391565b60405161012793929190611c41565b60405180910390f35b34801561013c57600080fd5b5061015061014b366004611c8e565b610446565b005b34801561015e57600080fd5b5061017261016d366004611d1b565b610566565b604051610127929190611dc6565b34801561018c57600080fd5b506101a061019b366004611de9565b6108d8565b604051908152602001610127565b6101506101bc366004611e43565b610a68565b3480156101cd57600080fd5b506101f06101dc366004611bd0565b600090815260056020526040902054151590565b6040519015158152602001610127565b34801561020c57600080fd5b5061015061021b366004611e7f565b610c15565b34801561022c57600080fd5b506101a061023b366004611efe565b610d30565b34801561024c57600080fd5b5061026061025b366004611fcf565b610fa4565b60405161012793929190612069565b34801561027b57600080fd5b506101a061028a366004612100565b60046020526000908152604090205481565b3480156102a857600080fd5b506101f06102b7366004612122565b6111ed565b3480156102c857600080fd5b506101f06102d7366004611c8e565b600360209081526000928352604080842090915290825290205460ff1681565b34801561030357600080fd5b506101a06103123660046121ab565b61130a565b34801561032357600080fd5b50610150610332366004612249565b611589565b34801561034357600080fd5b50610357610352366004612280565b61162f565b6040516101279190612384565b34801561037057600080fd5b506101a061037f366004612100565b60016020526000908152604090205481565b6000602081905290815260409020805460018201546002830180546001600160a01b039093169391926103c3906123ca565b80601f01602080910402602001604051908101604052809291908181526020018280546103ef906123ca565b801561043c5780601f106104115761010080835404028352916020019161043c565b820191906000526020600020905b81548152906001019060200180831161041f57829003601f168201915b5050505050905083565b336000818152600160205260408120805491924692309290859061046990612405565b91829055506040805160208101959095526bffffffffffffffffffffffff19606094851b8116918601919091529190921b166054830152606882015260880160408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606087811b82169385019390935233831b811660348501529185901b90911660488301529150605c0160408051808303601f19018152828252805160209182012060008581526002835292909220919091556001600160a01b03848116835283923392918716917fd48d52c7c6d0c940f3f8d07591e1800ef3a70daf79929a97ccd80b4494769fc7910160405180910390a4505050565b60008881526005602090815260408083205490516bffffffffffffffffffffffff1960608c811b82169483019490945233841b811660348301528a841b1660488201526001600160e01b03198916605c820152820160405160208183030381529060405280519060200120146106235760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e74000000000060448201526064015b60405180910390fd5b886001600160a01b03166106e585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516106df925061067f91508f908c908c9060200161243d565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b906117b0565b6001600160a01b03161461073b5760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e6174757265000000000000000000000000000000604482015260640161061a565b60008a81526005602052604080822091909155516001600160a01b03891690889061076e908d908a908a90602401612480565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516107c1919061249a565b6000604051808303816000865af19150503d80600081146107fe576040519150601f19603f3d011682016040523d82523d6000602084013e610803565b606091505b50909250905081156108585789896001600160a01b03167fc0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a888860405161084b9291906124b6565b60405180910390a36108cb565b89896001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc6040516108c2906020808252601f908201527f46756c66696c6c6d656e74206661696c656420756e65787065637465646c7900604082015260600190565b60405180910390a35b9850989650505050505050565b60006001600160a01b0385166109305760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b8484848460405160200161094794939291906124ca565b6040516020818303038152906040528051906020012090506040518060600160405280866001600160a01b0316815260200185815260200184848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509390945250508381526020818152604091829020845181547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178155848201516001820155918401518051929350610a1e9260028501929190910190611b37565b50905050807fba204bad31c4ec4b9b54164af94ae10c4e7312f22c0f9c065d6319c928ec9e7a86868686604051610a5894939291906124fd565b60405180910390a2949350505050565b6040516bffffffffffffffffffffffff19606084811b8216602084015283811b8216603484015233901b166048820152605c0160408051601f1981840301815291815281516020928301206000868152600290935291205414610b0d5760405162461bcd60e51b815260206004820152601e60248201527f496e76616c6964207769746864726177616c2066756c66696c6c6d656e740000604482015260640161061a565b6000838152600260209081526040808320929092558151338152349181019190915284916001600160a01b0380851692908616917fadb4840bbd5f924665ae7e0e0c83de5c0fb40a98c9b57dba53a6c978127a622e910160405180910390a46000816001600160a01b03163460405160006040518083038185875af1925050503d8060008114610bb9576040519150601f19603f3d011682016040523d82523d6000602084013e610bbe565b606091505b5050905080610c0f5760405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c65640000000000000000000000000000000000604482015260640161061a565b50505050565b6000868152600560209081526040918290205491516bffffffffffffffffffffffff19606089811b82169383019390935233831b8116603483015287831b1660488201526001600160e01b03198616605c820152016040516020818303038152906040528051906020012014610ccd5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e740000000000604482015260640161061a565b600560008781526020019081526020016000206000905585856001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc8484604051610d209291906124b6565b60405180910390a3505050505050565b60006001600160a01b038916610d885760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b6001600160a01b038516301415610de15760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038716600090815260036020908152604080832033845290915290205460ff16610e545760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d8d604051602001610ea59c9b9a99989796959493929190612530565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff1960608e811b8216938501939093528a831b8116603485015289831b1660488401526001600160e01b03198816605c84015293500160408051601f1981840301815291815281516020928301206000858152600584528281209190915533815260049092528120805491610f3e83612405565b9190505550818a6001600160a01b03167f3a52c462346de2e9436a3868970892956828a11b9c43da1ed43740b12e1125ae8346338e8e8e8e8e8e8e604051610f8f9a999897969594939291906125bf565b60405180910390a35098975050505050505050565b606080808367ffffffffffffffff811115610fc157610fc1612631565b604051908082528060200260200182016040528015610fea578160200160208202803683370190505b5092508367ffffffffffffffff81111561100657611006612631565b60405190808252806020026020018201604052801561102f578160200160208202803683370190505b5091508367ffffffffffffffff81111561104b5761104b612631565b60405190808252806020026020018201604052801561107e57816020015b60608152602001906001900390816110695790505b50905060005b848110156111e55760008060008888858181106110a3576110a3612647565b90506020020135815260200190815260200160002090508060000160009054906101000a90046001600160a01b03168583815181106110e4576110e4612647565b60200260200101906001600160a01b031690816001600160a01b031681525050806001015484838151811061111b5761111b612647565b602002602001018181525050806002018054611136906123ca565b80601f0160208091040260200160405190810160405280929190818152602001828054611162906123ca565b80156111af5780601f10611184576101008083540402835291602001916111af565b820191906000526020600020905b81548152906001019060200180831161119257829003601f168201915b50505050508383815181106111c6576111c6612647565b60200260200101819052505080806111dd90612405565b915050611084565b509250925092565b6000805b878110156112f957600089898381811061120d5761120d612647565b90506020020160208101906112229190612100565b6040517f29b915b3000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b038a811660248301526044820189905287811660648301528681166084830152919250908216906329b915b39060a40160206040518083038186803b15801561129e57600080fd5b505afa1580156112b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d6919061265d565b156112e6576001925050506112ff565b50806112f181612405565b9150506111f1565b50600090505b979650505050505050565b6000878152602081905260408120546001600160a01b03168061136f5760405162461bcd60e51b815260206004820152601760248201527f54656d706c61746520646f6573206e6f74206578697374000000000000000000604482015260640161061a565b6001600160a01b0386163014156113c85760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038816600090815260036020908152604080832033845290915290205460ff1661143b5760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d60405160200161148a9b9a9998979695949392919061267a565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606086811b8216938501939093528b831b811660348501528a831b1660488401526001600160e01b03198916605c84015294500160408051601f198184030181529181528151602092830120600086815260058452828120919091553381526004909252812080549161152383612405565b919050555082826001600160a01b03167feb39930cdcbb560e6422558a2468b93a215af60063622e63cbb165eba14c32038346338f8f8f8f8f8f8f6040516115749a999897969594939291906125bf565b60405180910390a35050979650505050505050565b6001600160a01b0382166000908152600460205260409020546115c3576001600160a01b0382166000908152600460205260409020600190555b3360008181526003602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917fc2e532a12bbcce2bfa2ef9e4bee80180e4e1b1f78618f0d20bc49a648b577c56910160405180910390a35050565b6060878614801561163f57508784145b801561164a57508782145b6116965760405162461bcd60e51b815260206004820152601960248201527f556e657175616c20706172616d65746572206c656e6774687300000000000000604482015260640161061a565b8767ffffffffffffffff8111156116af576116af612631565b6040519080825280602002602001820160405280156116d8578160200160208202803683370190505b50905060005b888110156117a05761176c8d8d8d8d8d868181106116fe576116fe612647565b905060200201358c8c8781811061171757611717612647565b905060200201358b8b8881811061173057611730612647565b90506020020160208101906117459190612100565b8a8a8981811061175757611757612647565b90506020020160208101906102b79190612100565b82828151811061177e5761177e612647565b911515602092830291909101909101528061179881612405565b9150506116de565b509b9a5050505050505050505050565b60008060006117bf85856117d4565b915091506117cc81611844565b509392505050565b60008082516041141561180b5760208301516040840151606085015160001a6117ff87828585611a02565b9450945050505061183d565b825160401415611835576020830151604084015161182a868383611aef565b93509350505061183d565b506000905060025b9250929050565b600081600481111561185857611858612701565b14156118615750565b600181600481111561187557611875612701565b14156118c35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161061a565b60028160048111156118d7576118d7612701565b14156119255760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161061a565b600381600481111561193957611939612701565b14156119925760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161061a565b60048160048111156119a6576119a6612701565b14156119ff5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161061a565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611a395750600090506003611ae6565b8460ff16601b14158015611a5157508460ff16601c14155b15611a625750600090506004611ae6565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611ab6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611adf57600060019250925050611ae6565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b01611b2987828885611a02565b935093505050935093915050565b828054611b43906123ca565b90600052602060002090601f016020900481019282611b655760008555611bab565b82601f10611b7e57805160ff1916838001178555611bab565b82800160010185558215611bab579182015b82811115611bab578251825591602001919060010190611b90565b50611bb7929150611bbb565b5090565b5b80821115611bb75760008155600101611bbc565b600060208284031215611be257600080fd5b5035919050565b60005b83811015611c04578181015183820152602001611bec565b83811115610c0f5750506000910152565b60008151808452611c2d816020860160208601611be9565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201526000611c696060830184611c15565b95945050505050565b80356001600160a01b0381168114611c8957600080fd5b919050565b60008060408385031215611ca157600080fd5b611caa83611c72565b9150611cb860208401611c72565b90509250929050565b80356001600160e01b031981168114611c8957600080fd5b60008083601f840112611ceb57600080fd5b50813567ffffffffffffffff811115611d0357600080fd5b60208301915083602082850101111561183d57600080fd5b60008060008060008060008060c0898b031215611d3757600080fd5b88359750611d4760208a01611c72565b9650611d5560408a01611c72565b9550611d6360608a01611cc1565b9450608089013567ffffffffffffffff80821115611d8057600080fd5b611d8c8c838d01611cd9565b909650945060a08b0135915080821115611da557600080fd5b50611db28b828c01611cd9565b999c989b5096995094979396929594505050565b8215158152604060208201526000611de16040830184611c15565b949350505050565b60008060008060608587031215611dff57600080fd5b611e0885611c72565b935060208501359250604085013567ffffffffffffffff811115611e2b57600080fd5b611e3787828801611cd9565b95989497509550505050565b600080600060608486031215611e5857600080fd5b83359250611e6860208501611c72565b9150611e7660408501611c72565b90509250925092565b60008060008060008060a08789031215611e9857600080fd5b86359550611ea860208801611c72565b9450611eb660408801611c72565b9350611ec460608801611cc1565b9250608087013567ffffffffffffffff811115611ee057600080fd5b611eec89828a01611cd9565b979a9699509497509295939492505050565b60008060008060008060008060e0898b031215611f1a57600080fd5b611f2389611c72565b975060208901359650611f3860408a01611c72565b9550611f4660608a01611c72565b9450611f5460808a01611c72565b9350611f6260a08a01611cc1565b925060c089013567ffffffffffffffff811115611f7e57600080fd5b611db28b828c01611cd9565b60008083601f840112611f9c57600080fd5b50813567ffffffffffffffff811115611fb457600080fd5b6020830191508360208260051b850101111561183d57600080fd5b60008060208385031215611fe257600080fd5b823567ffffffffffffffff811115611ff957600080fd5b61200585828601611f8a565b90969095509350505050565b600082825180855260208086019550808260051b84010181860160005b8481101561205c57601f1986840301895261204a838351611c15565b9884019892509083019060010161202e565b5090979650505050505050565b606080825284519082018190526000906020906080840190828801845b828110156120ab5781516001600160a01b031684529284019290840190600101612086565b5050508381038285015285518082528683019183019060005b818110156120e0578351835292840192918401916001016120c4565b505084810360408601526120f48187612011565b98975050505050505050565b60006020828403121561211257600080fd5b61211b82611c72565b9392505050565b600080600080600080600060c0888a03121561213d57600080fd5b873567ffffffffffffffff81111561215457600080fd5b6121608a828b01611f8a565b9098509650612173905060208901611c72565b9450604088013593506060880135925061218f60808901611c72565b915061219d60a08901611c72565b905092959891949750929550565b600080600080600080600060c0888a0312156121c657600080fd5b873596506121d660208901611c72565b95506121e460408901611c72565b94506121f260608901611c72565b935061220060808901611cc1565b925060a088013567ffffffffffffffff81111561221c57600080fd5b6122288a828b01611cd9565b989b979a50959850939692959293505050565b80151581146119ff57600080fd5b6000806040838503121561225c57600080fd5b61226583611c72565b915060208301356122758161223b565b809150509250929050565b600080600080600080600080600080600060c08c8e0312156122a157600080fd5b67ffffffffffffffff808d3511156122b857600080fd5b6122c58e8e358f01611f8a565b909c509a506122d660208e01611c72565b99508060408e013511156122e957600080fd5b6122f98e60408f01358f01611f8a565b909950975060608d013581101561230f57600080fd5b61231f8e60608f01358f01611f8a565b909750955060808d013581101561233557600080fd5b6123458e60808f01358f01611f8a565b909550935060a08d013581101561235b57600080fd5b5061236c8d60a08e01358e01611f8a565b81935080925050509295989b509295989b9093969950565b6020808252825182820181905260009190848201906040850190845b818110156123be5783511515835292840192918401916001016123a0565b50909695505050505050565b600181811c908216806123de57607f821691505b602082108114156123ff57634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561242757634e487b7160e01b600052601160045260246000fd5b5060010190565b81818437506000910190815290565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000611c69604083018486612457565b600082516124ac818460208701611be9565b9190910192915050565b602081526000611de1602083018486612457565b6bffffffffffffffffffffffff198560601b16815283601482015281836034830137600091016034019081529392505050565b6001600160a01b0385168152836020820152606060408201526000612526606083018486612457565b9695505050505050565b8c815260006bffffffffffffffffffffffff196060818f821b166020850152818e821b1660348501528c6048850152818c821b1660688501528a607c850152818a821b16609c8501528189821b1660b08501528188821b1660c485015250506001600160e01b0319851660d88301526125ad60dc8301848661242e565b9e9d5050505050505050505050505050565b60006101208c83528b60208401526001600160a01b03808c1660408501528a6060850152808a16608085015280891660a085015280881660c0850152506001600160e01b0319861660e0840152806101008401526126208184018587612457565b9d9c50505050505050505050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561266f57600080fd5b815161211b8161223b565b8b815260006bffffffffffffffffffffffff19808d60601b166020840152808c60601b1660348401528a6048840152896068840152808960601b166088840152808860601b16609c840152808760601b1660b0840152506001600160e01b0319851660c4830152828460c8840137506000910160c8019081529a9950505050505050505050565b634e487b7160e01b600052602160045260246000fdfea26469706673582212202bb1f23009421470aa9108e2354fefb6c982340337b4e63bcc7fa409ab66937d64736f6c63430008090033", - "deployedBytecode": "0x6080604052600436106100f35760003560e01c806376428c9b1161008a578063acbe180011610059578063acbe1800146102f7578063addf027c14610317578063ca31d58614610337578063f8fa73a11461036457600080fd5b806376428c9b146102405780637e7166f31461026f5780638a33be011461029c578063a81e9f79146102bc57600080fd5b80633c7fe5e3116100c65780633c7fe5e3146101ae57806350743bb9146101c157806352e41f99146102005780636e6be03f1461022057600080fd5b80630a631576146100f85780631d414cbd146101305780631decbf181461015257806332393f2b14610180575b600080fd5b34801561010457600080fd5b50610118610113366004611bd0565b610391565b60405161012793929190611c41565b60405180910390f35b34801561013c57600080fd5b5061015061014b366004611c8e565b610446565b005b34801561015e57600080fd5b5061017261016d366004611d1b565b610566565b604051610127929190611dc6565b34801561018c57600080fd5b506101a061019b366004611de9565b6108d8565b604051908152602001610127565b6101506101bc366004611e43565b610a68565b3480156101cd57600080fd5b506101f06101dc366004611bd0565b600090815260056020526040902054151590565b6040519015158152602001610127565b34801561020c57600080fd5b5061015061021b366004611e7f565b610c15565b34801561022c57600080fd5b506101a061023b366004611efe565b610d30565b34801561024c57600080fd5b5061026061025b366004611fcf565b610fa4565b60405161012793929190612069565b34801561027b57600080fd5b506101a061028a366004612100565b60046020526000908152604090205481565b3480156102a857600080fd5b506101f06102b7366004612122565b6111ed565b3480156102c857600080fd5b506101f06102d7366004611c8e565b600360209081526000928352604080842090915290825290205460ff1681565b34801561030357600080fd5b506101a06103123660046121ab565b61130a565b34801561032357600080fd5b50610150610332366004612249565b611589565b34801561034357600080fd5b50610357610352366004612280565b61162f565b6040516101279190612384565b34801561037057600080fd5b506101a061037f366004612100565b60016020526000908152604090205481565b6000602081905290815260409020805460018201546002830180546001600160a01b039093169391926103c3906123ca565b80601f01602080910402602001604051908101604052809291908181526020018280546103ef906123ca565b801561043c5780601f106104115761010080835404028352916020019161043c565b820191906000526020600020905b81548152906001019060200180831161041f57829003601f168201915b5050505050905083565b336000818152600160205260408120805491924692309290859061046990612405565b91829055506040805160208101959095526bffffffffffffffffffffffff19606094851b8116918601919091529190921b166054830152606882015260880160408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606087811b82169385019390935233831b811660348501529185901b90911660488301529150605c0160408051808303601f19018152828252805160209182012060008581526002835292909220919091556001600160a01b03848116835283923392918716917fd48d52c7c6d0c940f3f8d07591e1800ef3a70daf79929a97ccd80b4494769fc7910160405180910390a4505050565b60008881526005602090815260408083205490516bffffffffffffffffffffffff1960608c811b82169483019490945233841b811660348301528a841b1660488201526001600160e01b03198916605c820152820160405160208183030381529060405280519060200120146106235760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e74000000000060448201526064015b60405180910390fd5b886001600160a01b03166106e585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516106df925061067f91508f908c908c9060200161243d565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b906117b0565b6001600160a01b03161461073b5760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e6174757265000000000000000000000000000000604482015260640161061a565b60008a81526005602052604080822091909155516001600160a01b03891690889061076e908d908a908a90602401612480565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516107c1919061249a565b6000604051808303816000865af19150503d80600081146107fe576040519150601f19603f3d011682016040523d82523d6000602084013e610803565b606091505b50909250905081156108585789896001600160a01b03167fc0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a888860405161084b9291906124b6565b60405180910390a36108cb565b89896001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc6040516108c2906020808252601f908201527f46756c66696c6c6d656e74206661696c656420756e65787065637465646c7900604082015260600190565b60405180910390a35b9850989650505050505050565b60006001600160a01b0385166109305760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b8484848460405160200161094794939291906124ca565b6040516020818303038152906040528051906020012090506040518060600160405280866001600160a01b0316815260200185815260200184848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509390945250508381526020818152604091829020845181547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178155848201516001820155918401518051929350610a1e9260028501929190910190611b37565b50905050807fba204bad31c4ec4b9b54164af94ae10c4e7312f22c0f9c065d6319c928ec9e7a86868686604051610a5894939291906124fd565b60405180910390a2949350505050565b6040516bffffffffffffffffffffffff19606084811b8216602084015283811b8216603484015233901b166048820152605c0160408051601f1981840301815291815281516020928301206000868152600290935291205414610b0d5760405162461bcd60e51b815260206004820152601e60248201527f496e76616c6964207769746864726177616c2066756c66696c6c6d656e740000604482015260640161061a565b6000838152600260209081526040808320929092558151338152349181019190915284916001600160a01b0380851692908616917fadb4840bbd5f924665ae7e0e0c83de5c0fb40a98c9b57dba53a6c978127a622e910160405180910390a46000816001600160a01b03163460405160006040518083038185875af1925050503d8060008114610bb9576040519150601f19603f3d011682016040523d82523d6000602084013e610bbe565b606091505b5050905080610c0f5760405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c65640000000000000000000000000000000000604482015260640161061a565b50505050565b6000868152600560209081526040918290205491516bffffffffffffffffffffffff19606089811b82169383019390935233831b8116603483015287831b1660488201526001600160e01b03198616605c820152016040516020818303038152906040528051906020012014610ccd5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726571756573742066756c66696c6c6d656e740000000000604482015260640161061a565b600560008781526020019081526020016000206000905585856001600160a01b03167fc7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc8484604051610d209291906124b6565b60405180910390a3505050505050565b60006001600160a01b038916610d885760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f000000000000000000000000604482015260640161061a565b6001600160a01b038516301415610de15760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038716600090815260036020908152604080832033845290915290205460ff16610e545760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d8d604051602001610ea59c9b9a99989796959493929190612530565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff1960608e811b8216938501939093528a831b8116603485015289831b1660488401526001600160e01b03198816605c84015293500160408051601f1981840301815291815281516020928301206000858152600584528281209190915533815260049092528120805491610f3e83612405565b9190505550818a6001600160a01b03167f3a52c462346de2e9436a3868970892956828a11b9c43da1ed43740b12e1125ae8346338e8e8e8e8e8e8e604051610f8f9a999897969594939291906125bf565b60405180910390a35098975050505050505050565b606080808367ffffffffffffffff811115610fc157610fc1612631565b604051908082528060200260200182016040528015610fea578160200160208202803683370190505b5092508367ffffffffffffffff81111561100657611006612631565b60405190808252806020026020018201604052801561102f578160200160208202803683370190505b5091508367ffffffffffffffff81111561104b5761104b612631565b60405190808252806020026020018201604052801561107e57816020015b60608152602001906001900390816110695790505b50905060005b848110156111e55760008060008888858181106110a3576110a3612647565b90506020020135815260200190815260200160002090508060000160009054906101000a90046001600160a01b03168583815181106110e4576110e4612647565b60200260200101906001600160a01b031690816001600160a01b031681525050806001015484838151811061111b5761111b612647565b602002602001018181525050806002018054611136906123ca565b80601f0160208091040260200160405190810160405280929190818152602001828054611162906123ca565b80156111af5780601f10611184576101008083540402835291602001916111af565b820191906000526020600020905b81548152906001019060200180831161119257829003601f168201915b50505050508383815181106111c6576111c6612647565b60200260200101819052505080806111dd90612405565b915050611084565b509250925092565b6000805b878110156112f957600089898381811061120d5761120d612647565b90506020020160208101906112229190612100565b6040517f29b915b3000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b038a811660248301526044820189905287811660648301528681166084830152919250908216906329b915b39060a40160206040518083038186803b15801561129e57600080fd5b505afa1580156112b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d6919061265d565b156112e6576001925050506112ff565b50806112f181612405565b9150506111f1565b50600090505b979650505050505050565b6000878152602081905260408120546001600160a01b03168061136f5760405162461bcd60e51b815260206004820152601760248201527f54656d706c61746520646f6573206e6f74206578697374000000000000000000604482015260640161061a565b6001600160a01b0386163014156113c85760405162461bcd60e51b815260206004820152601a60248201527f46756c66696c6c2061646472657373204169726e6f6465527270000000000000604482015260640161061a565b6001600160a01b038816600090815260036020908152604080832033845290915290205460ff1661143b5760405162461bcd60e51b815260206004820152601760248201527f526571756573746572206e6f742073706f6e736f726564000000000000000000604482015260640161061a565b600060046000336001600160a01b03166001600160a01b03168152602001908152602001600020549050463033838d8d8d8d8d8d8d60405160200161148a9b9a9998979695949392919061267a565b60408051601f198184030181529082905280516020918201206bffffffffffffffffffffffff19606086811b8216938501939093528b831b811660348501528a831b1660488401526001600160e01b03198916605c84015294500160408051601f198184030181529181528151602092830120600086815260058452828120919091553381526004909252812080549161152383612405565b919050555082826001600160a01b03167feb39930cdcbb560e6422558a2468b93a215af60063622e63cbb165eba14c32038346338f8f8f8f8f8f8f6040516115749a999897969594939291906125bf565b60405180910390a35050979650505050505050565b6001600160a01b0382166000908152600460205260409020546115c3576001600160a01b0382166000908152600460205260409020600190555b3360008181526003602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917fc2e532a12bbcce2bfa2ef9e4bee80180e4e1b1f78618f0d20bc49a648b577c56910160405180910390a35050565b6060878614801561163f57508784145b801561164a57508782145b6116965760405162461bcd60e51b815260206004820152601960248201527f556e657175616c20706172616d65746572206c656e6774687300000000000000604482015260640161061a565b8767ffffffffffffffff8111156116af576116af612631565b6040519080825280602002602001820160405280156116d8578160200160208202803683370190505b50905060005b888110156117a05761176c8d8d8d8d8d868181106116fe576116fe612647565b905060200201358c8c8781811061171757611717612647565b905060200201358b8b8881811061173057611730612647565b90506020020160208101906117459190612100565b8a8a8981811061175757611757612647565b90506020020160208101906102b79190612100565b82828151811061177e5761177e612647565b911515602092830291909101909101528061179881612405565b9150506116de565b509b9a5050505050505050505050565b60008060006117bf85856117d4565b915091506117cc81611844565b509392505050565b60008082516041141561180b5760208301516040840151606085015160001a6117ff87828585611a02565b9450945050505061183d565b825160401415611835576020830151604084015161182a868383611aef565b93509350505061183d565b506000905060025b9250929050565b600081600481111561185857611858612701565b14156118615750565b600181600481111561187557611875612701565b14156118c35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161061a565b60028160048111156118d7576118d7612701565b14156119255760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161061a565b600381600481111561193957611939612701565b14156119925760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161061a565b60048160048111156119a6576119a6612701565b14156119ff5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161061a565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611a395750600090506003611ae6565b8460ff16601b14158015611a5157508460ff16601c14155b15611a625750600090506004611ae6565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611ab6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611adf57600060019250925050611ae6565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b01611b2987828885611a02565b935093505050935093915050565b828054611b43906123ca565b90600052602060002090601f016020900481019282611b655760008555611bab565b82601f10611b7e57805160ff1916838001178555611bab565b82800160010185558215611bab579182015b82811115611bab578251825591602001919060010190611b90565b50611bb7929150611bbb565b5090565b5b80821115611bb75760008155600101611bbc565b600060208284031215611be257600080fd5b5035919050565b60005b83811015611c04578181015183820152602001611bec565b83811115610c0f5750506000910152565b60008151808452611c2d816020860160208601611be9565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201526000611c696060830184611c15565b95945050505050565b80356001600160a01b0381168114611c8957600080fd5b919050565b60008060408385031215611ca157600080fd5b611caa83611c72565b9150611cb860208401611c72565b90509250929050565b80356001600160e01b031981168114611c8957600080fd5b60008083601f840112611ceb57600080fd5b50813567ffffffffffffffff811115611d0357600080fd5b60208301915083602082850101111561183d57600080fd5b60008060008060008060008060c0898b031215611d3757600080fd5b88359750611d4760208a01611c72565b9650611d5560408a01611c72565b9550611d6360608a01611cc1565b9450608089013567ffffffffffffffff80821115611d8057600080fd5b611d8c8c838d01611cd9565b909650945060a08b0135915080821115611da557600080fd5b50611db28b828c01611cd9565b999c989b5096995094979396929594505050565b8215158152604060208201526000611de16040830184611c15565b949350505050565b60008060008060608587031215611dff57600080fd5b611e0885611c72565b935060208501359250604085013567ffffffffffffffff811115611e2b57600080fd5b611e3787828801611cd9565b95989497509550505050565b600080600060608486031215611e5857600080fd5b83359250611e6860208501611c72565b9150611e7660408501611c72565b90509250925092565b60008060008060008060a08789031215611e9857600080fd5b86359550611ea860208801611c72565b9450611eb660408801611c72565b9350611ec460608801611cc1565b9250608087013567ffffffffffffffff811115611ee057600080fd5b611eec89828a01611cd9565b979a9699509497509295939492505050565b60008060008060008060008060e0898b031215611f1a57600080fd5b611f2389611c72565b975060208901359650611f3860408a01611c72565b9550611f4660608a01611c72565b9450611f5460808a01611c72565b9350611f6260a08a01611cc1565b925060c089013567ffffffffffffffff811115611f7e57600080fd5b611db28b828c01611cd9565b60008083601f840112611f9c57600080fd5b50813567ffffffffffffffff811115611fb457600080fd5b6020830191508360208260051b850101111561183d57600080fd5b60008060208385031215611fe257600080fd5b823567ffffffffffffffff811115611ff957600080fd5b61200585828601611f8a565b90969095509350505050565b600082825180855260208086019550808260051b84010181860160005b8481101561205c57601f1986840301895261204a838351611c15565b9884019892509083019060010161202e565b5090979650505050505050565b606080825284519082018190526000906020906080840190828801845b828110156120ab5781516001600160a01b031684529284019290840190600101612086565b5050508381038285015285518082528683019183019060005b818110156120e0578351835292840192918401916001016120c4565b505084810360408601526120f48187612011565b98975050505050505050565b60006020828403121561211257600080fd5b61211b82611c72565b9392505050565b600080600080600080600060c0888a03121561213d57600080fd5b873567ffffffffffffffff81111561215457600080fd5b6121608a828b01611f8a565b9098509650612173905060208901611c72565b9450604088013593506060880135925061218f60808901611c72565b915061219d60a08901611c72565b905092959891949750929550565b600080600080600080600060c0888a0312156121c657600080fd5b873596506121d660208901611c72565b95506121e460408901611c72565b94506121f260608901611c72565b935061220060808901611cc1565b925060a088013567ffffffffffffffff81111561221c57600080fd5b6122288a828b01611cd9565b989b979a50959850939692959293505050565b80151581146119ff57600080fd5b6000806040838503121561225c57600080fd5b61226583611c72565b915060208301356122758161223b565b809150509250929050565b600080600080600080600080600080600060c08c8e0312156122a157600080fd5b67ffffffffffffffff808d3511156122b857600080fd5b6122c58e8e358f01611f8a565b909c509a506122d660208e01611c72565b99508060408e013511156122e957600080fd5b6122f98e60408f01358f01611f8a565b909950975060608d013581101561230f57600080fd5b61231f8e60608f01358f01611f8a565b909750955060808d013581101561233557600080fd5b6123458e60808f01358f01611f8a565b909550935060a08d013581101561235b57600080fd5b5061236c8d60a08e01358e01611f8a565b81935080925050509295989b509295989b9093969950565b6020808252825182820181905260009190848201906040850190845b818110156123be5783511515835292840192918401916001016123a0565b50909695505050505050565b600181811c908216806123de57607f821691505b602082108114156123ff57634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561242757634e487b7160e01b600052601160045260246000fd5b5060010190565b81818437506000910190815290565b838152818360208301376000910160200190815292915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000611c69604083018486612457565b600082516124ac818460208701611be9565b9190910192915050565b602081526000611de1602083018486612457565b6bffffffffffffffffffffffff198560601b16815283601482015281836034830137600091016034019081529392505050565b6001600160a01b0385168152836020820152606060408201526000612526606083018486612457565b9695505050505050565b8c815260006bffffffffffffffffffffffff196060818f821b166020850152818e821b1660348501528c6048850152818c821b1660688501528a607c850152818a821b16609c8501528189821b1660b08501528188821b1660c485015250506001600160e01b0319851660d88301526125ad60dc8301848661242e565b9e9d5050505050505050505050505050565b60006101208c83528b60208401526001600160a01b03808c1660408501528a6060850152808a16608085015280891660a085015280881660c0850152506001600160e01b0319861660e0840152806101008401526126208184018587612457565b9d9c50505050505050505050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561266f57600080fd5b815161211b8161223b565b8b815260006bffffffffffffffffffffffff19808d60601b166020840152808c60601b1660348401528a6048840152896068840152808960601b166088840152808860601b16609c840152808760601b1660b0840152506001600160e01b0319851660c4830152828460c8840137506000910160c8019081529a9950505050505050505050565b634e487b7160e01b600052602160045260246000fdfea26469706673582212202bb1f23009421470aa9108e2354fefb6c982340337b4e63bcc7fa409ab66937d64736f6c63430008090033", + "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": { @@ -1039,15 +1039,15 @@ "storageLayout": { "storage": [ { - "astId": 3541, + "astId": 3643, "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", "label": "templates", "offset": 0, "slot": "0", - "type": "t_mapping(t_bytes32,t_struct(Template)3534_storage)" + "type": "t_mapping(t_bytes32,t_struct(Template)3636_storage)" }, { - "astId": 3694, + "astId": 3796, "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", "label": "sponsorToWithdrawalRequestCount", "offset": 0, @@ -1055,7 +1055,7 @@ "type": "t_mapping(t_address,t_uint256)" }, { - "astId": 3699, + "astId": 3801, "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", "label": "withdrawalRequestIdToParameters", "offset": 0, @@ -1136,19 +1136,19 @@ "numberOfBytes": "32", "value": "t_bytes32" }, - "t_mapping(t_bytes32,t_struct(Template)3534_storage)": { + "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)3534_storage" + "value": "t_struct(Template)3636_storage" }, - "t_struct(Template)3534_storage": { + "t_struct(Template)3636_storage": { "encoding": "inplace", "label": "struct TemplateUtilsV0.Template", "members": [ { - "astId": 3529, + "astId": 3631, "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", "label": "airnode", "offset": 0, @@ -1156,7 +1156,7 @@ "type": "t_address" }, { - "astId": 3531, + "astId": 3633, "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", "label": "endpointId", "offset": 0, @@ -1164,7 +1164,7 @@ "type": "t_bytes32" }, { - "astId": 3533, + "astId": 3635, "contract": "contracts/rrp/AirnodeRrpV0.sol:AirnodeRrpV0", "label": "parameters", "offset": 0, diff --git a/packages/airnode-protocol/deployments/boba-avalanche/AirnodeRrpV0DryRun.json b/packages/airnode-protocol/deployments/mantle/AirnodeRrpV0DryRun.json similarity index 98% rename from packages/airnode-protocol/deployments/boba-avalanche/AirnodeRrpV0DryRun.json rename to packages/airnode-protocol/deployments/mantle/AirnodeRrpV0DryRun.json index cb0aae2f79..894c860b6f 100644 --- a/packages/airnode-protocol/deployments/boba-avalanche/AirnodeRrpV0DryRun.json +++ b/packages/airnode-protocol/deployments/mantle/AirnodeRrpV0DryRun.json @@ -76,25 +76,25 @@ "type": "function" } ], - "transactionHash": "0xae00c0f62d48cd88e9fc0ff2dc5143b09f63ffc1de7fbbe71a05b6def36ff94c", + "transactionHash": "0x55188d56a2b4b978932726052003e767d027e77d33404155df49c18e36709d28", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", "contractAddress": null, "transactionIndex": 0, - "gasUsed": "653829", + "gasUsed": "582904", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xe20ccc5b2ebd2c8d5e050f859cdacbf39856ebbc3a9ecf25e085a53e209a4497", - "transactionHash": "0xae00c0f62d48cd88e9fc0ff2dc5143b09f63ffc1de7fbbe71a05b6def36ff94c", + "blockHash": "0x8d003a53d0b55f1d95c412e6810fd529713b7e81a14b8c99b7a5e04425b8f39c", + "transactionHash": "0x55188d56a2b4b978932726052003e767d027e77d33404155df49c18e36709d28", "logs": [], - "blockNumber": 70462, - "cumulativeGasUsed": "653829", + "blockNumber": 1803739, + "cumulativeGasUsed": "582904", "status": 1, "byzantium": true }, "args": [], "numDeployments": 1, - "solcInputHash": "91bdad71ba8d8c57da42984f65eb24cc", + "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", @@ -137,7 +137,7 @@ "storageLayout": { "storage": [ { - "astId": 4985, + "astId": 3386, "contract": "contracts/rrp/AirnodeRrpV0DryRun.sol:AirnodeRrpV0DryRun", "label": "requestIdToFulfillmentParameters", "offset": 0, diff --git a/packages/airnode-protocol/deployments/boba-avalanche/RequesterAuthorizerWithAirnode.json b/packages/airnode-protocol/deployments/mantle/RequesterAuthorizerWithAirnode.json similarity index 99% rename from packages/airnode-protocol/deployments/boba-avalanche/RequesterAuthorizerWithAirnode.json rename to packages/airnode-protocol/deployments/mantle/RequesterAuthorizerWithAirnode.json index 687f8021c8..3aee48fe27 100644 --- a/packages/airnode-protocol/deployments/boba-avalanche/RequesterAuthorizerWithAirnode.json +++ b/packages/airnode-protocol/deployments/mantle/RequesterAuthorizerWithAirnode.json @@ -586,25 +586,25 @@ "type": "function" } ], - "transactionHash": "0x3cf413f8fb90231746351c308f67923c421af6ddb9ca2000da49ab2b178ed770", + "transactionHash": "0xdec691b576555cef3f043cde5b5aa3859686fe31ae96b524510c7f512d185e22", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", "contractAddress": null, "transactionIndex": 0, - "gasUsed": "1712520", + "gasUsed": "1570550", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x33492822bb6d505e506cfa1462706d7eb762848f8487c7dd47e4369272c8f9e2", - "transactionHash": "0x3cf413f8fb90231746351c308f67923c421af6ddb9ca2000da49ab2b178ed770", + "blockHash": "0x690e44d56221827f170b1694dacbc52624b10f5d52424d04114270c03f99880d", + "transactionHash": "0xdec691b576555cef3f043cde5b5aa3859686fe31ae96b524510c7f512d185e22", "logs": [], - "blockNumber": 29168, - "cumulativeGasUsed": "1712520", + "blockNumber": 1803726, + "cumulativeGasUsed": "1570550", "status": 1, "byzantium": true }, "args": ["0x92E5125adF385d86beDb950793526106143b6Df1", "RequesterAuthorizerWithAirnode admin"], "numDeployments": 1, - "solcInputHash": "0ab40609a497e05bef785ddb4724b7a0", + "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", @@ -802,15 +802,15 @@ "type": "t_string_storage" }, { - "astId": 4995, + "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)4988_storage))" + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_struct(WhitelistStatus)5211_storage))" }, { - "astId": 5003, + "astId": 5226, "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", "label": "serviceIdToUserToSetterToIndefiniteWhitelistStatus", "offset": 0, @@ -848,12 +848,12 @@ "numberOfBytes": "32", "value": "t_mapping(t_address,t_bool)" }, - "t_mapping(t_address,t_struct(WhitelistStatus)4988_storage)": { + "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)4988_storage" + "value": "t_struct(WhitelistStatus)5211_storage" }, "t_mapping(t_bytes32,t_mapping(t_address,t_mapping(t_address,t_bool)))": { "encoding": "mapping", @@ -862,24 +862,24 @@ "numberOfBytes": "32", "value": "t_mapping(t_address,t_mapping(t_address,t_bool))" }, - "t_mapping(t_bytes32,t_mapping(t_address,t_struct(WhitelistStatus)4988_storage))": { + "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)4988_storage)" + "value": "t_mapping(t_address,t_struct(WhitelistStatus)5211_storage)" }, "t_string_storage": { "encoding": "bytes", "label": "string", "numberOfBytes": "32" }, - "t_struct(WhitelistStatus)4988_storage": { + "t_struct(WhitelistStatus)5211_storage": { "encoding": "inplace", "label": "struct Whitelist.WhitelistStatus", "members": [ { - "astId": 4985, + "astId": 5208, "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", "label": "expirationTimestamp", "offset": 0, @@ -887,7 +887,7 @@ "type": "t_uint64" }, { - "astId": 4987, + "astId": 5210, "contract": "contracts/authorizers/RequesterAuthorizerWithAirnode.sol:RequesterAuthorizerWithAirnode", "label": "indefiniteWhitelistCount", "offset": 8, diff --git a/packages/airnode-protocol/deployments/mantle/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json b/packages/airnode-protocol/deployments/mantle/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json new file mode 100644 index 0000000000..d38c4a14fa --- /dev/null +++ b/packages/airnode-protocol/deployments/mantle/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/polygon-zkevm-goerli-testnet/.chainId b/packages/airnode-protocol/deployments/polygon-zkevm-goerli-testnet/.chainId new file mode 100644 index 0000000000..37a71f925f --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm-goerli-testnet/.chainId @@ -0,0 +1 @@ +1442 \ No newline at end of file diff --git a/packages/airnode-protocol/deployments/polygon-zkevm-goerli-testnet/AccessControlRegistry.json b/packages/airnode-protocol/deployments/polygon-zkevm-goerli-testnet/AccessControlRegistry.json new file mode 100644 index 0000000000..1ceaa47a1b --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm-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": "0xde770621122da0d8f9a26d1e5cd48d1dfadcbf4eb9caac2d5843b8fc93b49f29", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 0, + "gasUsed": "1006245", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x6283e0f25e2d40b6f3903d9392c17f42979b4617380b79527c556debb7c8567e", + "transactionHash": "0xde770621122da0d8f9a26d1e5cd48d1dfadcbf4eb9caac2d5843b8fc93b49f29", + "logs": [], + "blockNumber": 2037334, + "cumulativeGasUsed": "1006245", + "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/polygon-zkevm-goerli-testnet/AirnodeRrpV0.json b/packages/airnode-protocol/deployments/polygon-zkevm-goerli-testnet/AirnodeRrpV0.json new file mode 100644 index 0000000000..5ad3f84daf --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm-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": "0x440092dd6dde467138b00216ee43495b37fe341890bca13da8bbaf35e42d21a4", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 0, + "gasUsed": "2228110", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x099983bbb88cd2c95e2eeef5d5a1a2e483ef6733cdd091c3f3a9561234da6994", + "transactionHash": "0x440092dd6dde467138b00216ee43495b37fe341890bca13da8bbaf35e42d21a4", + "logs": [], + "blockNumber": 2037337, + "cumulativeGasUsed": "2228110", + "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/polygon-zkevm-goerli-testnet/AirnodeRrpV0DryRun.json b/packages/airnode-protocol/deployments/polygon-zkevm-goerli-testnet/AirnodeRrpV0DryRun.json new file mode 100644 index 0000000000..00c990b13f --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm-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": "0x6b580eab4ded10aa1faea4116af57570dad0071a33cf720fc2dcaf991afe09be", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 0, + "gasUsed": "582904", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x538c0be52b1a17fff0778425b39c7b6d60da786b81a4fc11dbeac973e3d8b2d6", + "transactionHash": "0x6b580eab4ded10aa1faea4116af57570dad0071a33cf720fc2dcaf991afe09be", + "logs": [], + "blockNumber": 2037338, + "cumulativeGasUsed": "582904", + "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/polygon-zkevm-goerli-testnet/RequesterAuthorizerWithAirnode.json b/packages/airnode-protocol/deployments/polygon-zkevm-goerli-testnet/RequesterAuthorizerWithAirnode.json new file mode 100644 index 0000000000..191da6f1ac --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm-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": "0xd6d8faecc68b5b5775e0e1e4315f0f04d2bc58cf6d4b678c285fb493031d9195", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 0, + "gasUsed": "1570550", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xf5370b81c9b94df2e0b365b645f74bc14637cce6580cc85e5d8d5a9bee3310aa", + "transactionHash": "0xd6d8faecc68b5b5775e0e1e4315f0f04d2bc58cf6d4b678c285fb493031d9195", + "logs": [], + "blockNumber": 2037335, + "cumulativeGasUsed": "1570550", + "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/polygon-zkevm-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json b/packages/airnode-protocol/deployments/polygon-zkevm-goerli-testnet/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json new file mode 100644 index 0000000000..d38c4a14fa --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm-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/polygon-zkevm/.chainId b/packages/airnode-protocol/deployments/polygon-zkevm/.chainId new file mode 100644 index 0000000000..1ea87ef70d --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm/.chainId @@ -0,0 +1 @@ +1101 \ No newline at end of file diff --git a/packages/airnode-protocol/deployments/polygon-zkevm/AccessControlRegistry.json b/packages/airnode-protocol/deployments/polygon-zkevm/AccessControlRegistry.json new file mode 100644 index 0000000000..499eeb09dc --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm/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": "0x708741415ffc54b951e39292d33590513cc57a788ba6d81a5b23a24b62065bdc", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 0, + "gasUsed": "1006245", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xe11126384f00f69ffdf3fc0b6d4ffa82fd677f7b9e71dffdf1afc580e3bbde92", + "transactionHash": "0x708741415ffc54b951e39292d33590513cc57a788ba6d81a5b23a24b62065bdc", + "logs": [], + "blockNumber": 4434673, + "cumulativeGasUsed": "1006245", + "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/polygon-zkevm/AirnodeRrpV0.json b/packages/airnode-protocol/deployments/polygon-zkevm/AirnodeRrpV0.json new file mode 100644 index 0000000000..1e4a26f440 --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm/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": "0x35809e26a6cdc80bdb8cf5d22456d04c1aebb23e5eecf6f14be8f3a041042354", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 0, + "gasUsed": "2228110", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x075bf72e094aaa26724cd9459ab8b89610a5cdb026cb455c03ab336eb636908f", + "transactionHash": "0x35809e26a6cdc80bdb8cf5d22456d04c1aebb23e5eecf6f14be8f3a041042354", + "logs": [], + "blockNumber": 4434685, + "cumulativeGasUsed": "2228110", + "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/polygon-zkevm/AirnodeRrpV0DryRun.json b/packages/airnode-protocol/deployments/polygon-zkevm/AirnodeRrpV0DryRun.json new file mode 100644 index 0000000000..6b40bbdb73 --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm/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": "0x18154e592d7a887d10baa091bf500946a1c4f2a29a4ad895e74e82ec99c48402", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 0, + "gasUsed": "582904", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x6bd3563c3c1667f45004521b53b4fcc9185ebad74b9f63de5604b99dccfce6e7", + "transactionHash": "0x18154e592d7a887d10baa091bf500946a1c4f2a29a4ad895e74e82ec99c48402", + "logs": [], + "blockNumber": 4434689, + "cumulativeGasUsed": "582904", + "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/polygon-zkevm/RequesterAuthorizerWithAirnode.json b/packages/airnode-protocol/deployments/polygon-zkevm/RequesterAuthorizerWithAirnode.json new file mode 100644 index 0000000000..3585fa4f3d --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm/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": "0x978d295315064f9479dd3f9da1a598af18b1944be2d0a2653c92fe35d66cfada", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0xBba33C9cB97a3eB9be85C5B9A8Da43D266d01c33", + "contractAddress": null, + "transactionIndex": 0, + "gasUsed": "1570550", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x8abed492bf472a94867c7f938533ae041a2c232dca3bcabb586f500724fe23e1", + "transactionHash": "0x978d295315064f9479dd3f9da1a598af18b1944be2d0a2653c92fe35d66cfada", + "logs": [], + "blockNumber": 4434680, + "cumulativeGasUsed": "1570550", + "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/polygon-zkevm/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json b/packages/airnode-protocol/deployments/polygon-zkevm/solcInputs/d8591a026515856ab7bc7dc284bf2fbe.json new file mode 100644 index 0000000000..d38c4a14fa --- /dev/null +++ b/packages/airnode-protocol/deployments/polygon-zkevm/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 9f74e3413c..df418349a6 100644 --- a/packages/airnode-protocol/deployments/references.json +++ b/packages/airnode-protocol/deployments/references.json @@ -1,43 +1,4 @@ { - "chainNames": { - "1": "ethereum", - "5": "ethereum-goerli-testnet", - "10": "optimism", - "30": "rsk", - "31": "rsk-testnet", - "56": "bsc", - "97": "bsc-testnet", - "100": "gnosis", - "137": "polygon", - "250": "fantom", - "288": "boba-ethereum", - "416": "sx", - "420": "optimism-goerli-testnet", - "599": "metis-goerli-testnet", - "647": "sx-testnet", - "1088": "metis", - "1284": "moonbeam", - "1285": "moonriver", - "1287": "moonbeam-testnet", - "2001": "milkomeda-c1", - "4002": "fantom-testnet", - "10200": "gnosis-testnet", - "42161": "arbitrum", - "42170": "arbitrum-nova", - "43113": "avalanche-testnet", - "43114": "avalanche", - "43288": "boba-avalanche", - "56288": "boba-bnb", - "71401": "godwoken-testnet", - "71402": "godwoken", - "80001": "polygon-testnet", - "200101": "milkomeda-c1-testnet", - "421613": "arbitrum-goerli-testnet", - "11155111": "ethereum-sepolia-testnet", - "168587773": "blast_sepolia", - "1313161554": "aurora", - "1313161555": "aurora-testnet" - }, "AccessControlRegistry": { "1": "0x92E5125adF385d86beDb950793526106143b6Df1", "5": "0x92E5125adF385d86beDb950793526106143b6Df1", @@ -55,21 +16,30 @@ "599": "0x81A850254769a6C87d4F11B9F80bCc5bE1CcF50E", "647": "0xD223DfDCb888CA1539bb3459a83c543A1608F038", "1088": "0xb015ACeEdD478fc497A798Ab45fcED8BdEd08924", + "1101": "0x92E5125adF385d86beDb950793526106143b6Df1", "1284": "0x92E5125adF385d86beDb950793526106143b6Df1", "1285": "0x92E5125adF385d86beDb950793526106143b6Df1", "1287": "0x92E5125adF385d86beDb950793526106143b6Df1", + "1442": "0x92E5125adF385d86beDb950793526106143b6Df1", + "1890": "0x92E5125adF385d86beDb950793526106143b6Df1", + "1891": "0x92E5125adF385d86beDb950793526106143b6Df1", "2001": "0x92E5125adF385d86beDb950793526106143b6Df1", "4002": "0x92E5125adF385d86beDb950793526106143b6Df1", + "5000": "0x92E5125adF385d86beDb950793526106143b6Df1", + "5001": "0xD223DfDCb888CA1539bb3459a83c543A1608F038", + "8453": "0x92E5125adF385d86beDb950793526106143b6Df1", "10200": "0x92E5125adF385d86beDb950793526106143b6Df1", "42161": "0x5aB00E30453EEAd35025A761ED65d51d74574C24", "42170": "0x92E5125adF385d86beDb950793526106143b6Df1", "43113": "0x5997C09be60196b7De9dE73C88dd7776f2875401", "43114": "0xb015ACeEdD478fc497A798Ab45fcED8BdEd08924", - "43288": "0x92E5125adF385d86beDb950793526106143b6Df1", "56288": "0xD223DfDCb888CA1539bb3459a83c543A1608F038", + "59140": "0x92E5125adF385d86beDb950793526106143b6Df1", + "59144": "0x92E5125adF385d86beDb950793526106143b6Df1", "71401": "0x92E5125adF385d86beDb950793526106143b6Df1", "71402": "0x8E7D155C6E124a5C2c8DE2AFFCd8702e3660E482", "80001": "0x92E5125adF385d86beDb950793526106143b6Df1", + "84531": "0x92E5125adF385d86beDb950793526106143b6Df1", "200101": "0x92E5125adF385d86beDb950793526106143b6Df1", "421613": "0x92E5125adF385d86beDb950793526106143b6Df1", "11155111": "0xF6d2675468989387e96127546e0CBC9A384fa418", @@ -94,21 +64,30 @@ "599": "0xe40f1a1A546B70003D9ddF66B89C261cA46A0CF0", "647": "0x4A0b644219d07fEa25B701AAf89b963576b468dC", "1088": "0x8262a9DAB3f8a0b1E6317551E214CeA89Bc3f56d", + "1101": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "1284": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "1285": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "1287": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "1442": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "1890": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "1891": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "2001": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "4002": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "5000": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "5001": "0x4A0b644219d07fEa25B701AAf89b963576b468dC", + "8453": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "10200": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "42161": "0x944609FF0729435F87Ef429EC155d7539A83B9C8", "42170": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "43113": "0x4923968942E8aae4656ae4913874EB7312e0F7c7", "43114": "0x8262a9DAB3f8a0b1E6317551E214CeA89Bc3f56d", - "43288": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "56288": "0x4A0b644219d07fEa25B701AAf89b963576b468dC", + "59140": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "59144": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "71401": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "71402": "0x7D15b4676c7FFfdcb69E838518B2182223aE46d3", "80001": "0xf18c105D0375E80980e4EED829a4A68A539E6178", + "84531": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "200101": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "421613": "0xf18c105D0375E80980e4EED829a4A68A539E6178", "11155111": "0x55D72F0eb10e85D390B20DA57aa3122312647c0d", @@ -133,21 +112,30 @@ "599": "0x5997C09be60196b7De9dE73C88dd7776f2875401", "647": "0x20C9e9610d4e719a39F82893b3f42e2730F42778", "1088": "0xC02Ea0f403d5f3D45a4F1d0d817e7A2601346c9E", + "1101": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "1284": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "1285": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "1287": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "1442": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "1890": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "1891": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "2001": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "4002": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "5000": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "5001": "0x20C9e9610d4e719a39F82893b3f42e2730F42778", + "8453": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "10200": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "42161": "0xb015ACeEdD478fc497A798Ab45fcED8BdEd08924", "42170": "0xd864A45334C7a632cA9149993682354D7f967F28", "43113": "0x7f5AF7a37a33898544717AAa6c35c111dCe95b28", "43114": "0xC02Ea0f403d5f3D45a4F1d0d817e7A2601346c9E", - "43288": "0xd864A45334C7a632cA9149993682354D7f967F28", "56288": "0x20C9e9610d4e719a39F82893b3f42e2730F42778", + "59140": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "59144": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "71401": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "71402": "0xb3070A0F2f84765Ee19EfADf91dfE50690a9eEa1", "80001": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", + "84531": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "200101": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "421613": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd", "11155111": "0x2ab9f26E18B64848cd349582ca3B55c2d06f507d", @@ -172,176 +160,35 @@ "599": "0x4923968942E8aae4656ae4913874EB7312e0F7c7", "647": "0x3e10e6eF3c602885a9Cafd9785BD2143c52fbFF1", "1088": "0xeefA1A591052DB4208C6BcD1E716B136E07cb692", + "1101": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "1284": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "1285": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "1287": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "1442": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "1890": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "1891": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "2001": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "4002": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "5000": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "5001": "0x3e10e6eF3c602885a9Cafd9785BD2143c52fbFF1", + "8453": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "10200": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "42161": "0x368A8C0a75fD707e4f7bF15DD1aA25ED554fE22c", "42170": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "43113": "0x705787063B11142a9a48F4D2f4bfB56214828261", "43114": "0x824cb5cE2894cBA4eDdd005c5029eD17F5FEcf99", - "43288": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "56288": "0xdCED7ECFf6941613e739A30AeADa0F4FB85e5724", + "59140": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "59144": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "71401": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "71402": "0xbe28bd4921345dC632B3a55114091Be37b2DB739", "80001": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", + "84531": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "200101": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "421613": "0x2e768206bf5112e7D7efAf1d9df614C26475193f", "11155111": "0xFb10b1b0f68b3EaAcA1eCD12a47Cf7F55BeabB98", "168587773": "0x4A0b644219d07fEa25B701AAf89b963576b468dC", "1313161554": "0x04b833bD6339570B01aff994A72ea33cF92bD0EF", "1313161555": "0x2e768206bf5112e7D7efAf1d9df614C26475193f" - }, - "networks": { - "1": { - "chainId": 1, - "name": "ethereum" - }, - "5": { - "chainId": 5, - "name": "ethereum-goerli-testnet" - }, - "10": { - "chainId": 10, - "name": "optimism" - }, - "30": { - "chainId": 30, - "name": "rsk" - }, - "31": { - "chainId": 31, - "name": "rsk-testnet" - }, - "56": { - "chainId": 56, - "name": "bsc" - }, - "97": { - "chainId": 97, - "name": "bsc-testnet" - }, - "100": { - "chainId": 100, - "name": "gnosis" - }, - "137": { - "chainId": 137, - "name": "polygon" - }, - "250": { - "chainId": 250, - "name": "fantom" - }, - "288": { - "chainId": 288, - "name": "boba-ethereum" - }, - "416": { - "chainId": 416, - "name": "sx" - }, - "420": { - "chainId": 420, - "name": "optimism-goerli-testnet" - }, - "599": { - "chainId": 599, - "name": "metis-goerli-testnet" - }, - "647": { - "chainId": 647, - "name": "sx-testnet" - }, - "1088": { - "chainId": 1088, - "name": "metis" - }, - "1284": { - "chainId": 1284, - "name": "moonbeam" - }, - "1285": { - "chainId": 1285, - "name": "moonriver" - }, - "1287": { - "chainId": 1287, - "name": "moonbeam-testnet" - }, - "2001": { - "chainId": 2001, - "name": "milkomeda-c1" - }, - "4002": { - "chainId": 4002, - "name": "fantom-testnet" - }, - "10200": { - "chainId": 10200, - "name": "gnosis-testnet" - }, - "42161": { - "chainId": 42161, - "name": "arbitrum" - }, - "42170": { - "chainId": 42170, - "name": "arbitrum-nova" - }, - "43113": { - "chainId": 43113, - "name": "avalanche-testnet" - }, - "43114": { - "chainId": 43114, - "name": "avalanche" - }, - "43288": { - "chainId": 43288, - "name": "boba-avalanche" - }, - "56288": { - "chainId": 56288, - "name": "boba-bnb" - }, - "71401": { - "chainId": 71401, - "name": "godwoken-testnet" - }, - "71402": { - "chainId": 71402, - "name": "godwoken" - }, - "80001": { - "chainId": 80001, - "name": "polygon-testnet" - }, - "200101": { - "chainId": 200101, - "name": "milkomeda-c1-testnet" - }, - "421613": { - "chainId": 421613, - "name": "arbitrum-goerli-testnet" - }, - "11155111": { - "chainId": 11155111, - "name": "ethereum-sepolia-testnet" - }, - "168587773": { - "chainId": 168587773, - "name": "blast_sepolia" - }, - "1313161554": { - "chainId": 1313161554, - "name": "aurora" - }, - "1313161555": { - "chainId": 1313161555, - "name": "aurora-testnet" - } } } diff --git a/packages/airnode-protocol/package.json b/packages/airnode-protocol/package.json index fd8c7f6250..fb610c42c1 100644 --- a/packages/airnode-protocol/package.json +++ b/packages/airnode-protocol/package.json @@ -1,7 +1,7 @@ { "name": "@api3/airnode-protocol", "license": "MIT", - "version": "0.12.0", + "version": "0.13.0", "private": false, "main": "dist/src/index", "files": [ @@ -10,7 +10,7 @@ ], "scripts": { "build": "yarn run clean && yarn compile", - "clean": "rimraf -g ./src/contracts *.tsbuildinfo ./dist ./build *.tgz", + "clean": "rimraf -g ./src/contracts *.tsbuildinfo ./dist ./build *.tgz && yarn run hardhat clean", "compile": "yarn run compile:contracts && yarn run compile:tsc", "compile:contracts": "hardhat compile", "compile:tsc": "yarn compile:contract-dts && yarn compile:copy-contract-dts && tsc --build tsconfig.json", @@ -29,24 +29,24 @@ "write-example-env-file": "hardhat run scripts/write-example-env-file.ts" }, "devDependencies": { - "@api3/chains": "^3.3.0", + "@api3/chains": "^4.3.0", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "^3.1.7", "@nomiclabs/hardhat-waffle": "^2.0.6", - "@typechain/ethers-v5": "^11.0.0", - "chai": "^4.3.7", + "@typechain/ethers-v5": "^11.1.2", + "chai": "^4.3.10", "copyfiles": "^2.4.1", "ethereum-waffle": "^4.0.10", "hardhat": "^2.14.1", - "hardhat-deploy": "^0.11.34", + "hardhat-deploy": "^0.11.43", "hardhat-gas-reporter": "^1.0.9", - "rimraf": "^5.0.1", - "solidity-coverage": "^0.8.4", - "typechain": "^8.2.0", - "typescript": "^5.1.6" + "rimraf": "^5.0.5", + "solidity-coverage": "^0.8.5", + "typechain": "^8.3.2", + "typescript": "^5.2.2" }, "dependencies": { - "@api3/airnode-protocol-v1": "^2.8.0", + "@api3/airnode-protocol-v1": "^3.1.0", "@openzeppelin/contracts": "4.4.2", "ethers": "^5.7.2" } diff --git a/packages/airnode-protocol/scripts/generate-references.ts b/packages/airnode-protocol/scripts/generate-references.ts index 94ceaf1f8c..7dba7db4b8 100644 --- a/packages/airnode-protocol/scripts/generate-references.ts +++ b/packages/airnode-protocol/scripts/generate-references.ts @@ -9,11 +9,6 @@ const networkNames = fs .map((item) => item.name); const references: any = {}; -references.chainNames = {}; - -for (const network of networkNames) { - references.chainNames[hre.config.networks[network].chainId] = network; -} for (const contractName of contractNames) { references[contractName] = {}; @@ -24,10 +19,4 @@ for (const contractName of contractNames) { } } -const networks = Object.entries(references.chainNames).reduce((acc, [chainId, name]) => { - if (name === 'mainnet') return { ...acc, [parseInt(chainId)]: { chainId: parseInt(chainId), name: 'homestead' } }; - return { ...acc, [parseInt(chainId)]: { chainId: parseInt(chainId), name } }; -}, {}); -references.networks = networks; - -fs.writeFileSync(path.join('deployments', 'references.json'), JSON.stringify(references, null, 2)); +fs.writeFileSync(path.join('deployments', 'references.json'), JSON.stringify(references, null, 2) + '\n'); diff --git a/packages/airnode-protocol/src/index.ts b/packages/airnode-protocol/src/index.ts index 90795cd3f4..7128484b9a 100644 --- a/packages/airnode-protocol/src/index.ts +++ b/packages/airnode-protocol/src/index.ts @@ -10,7 +10,6 @@ * * The generated code "value exports" the factories, but "type exports" the contracts. */ -import { ethers } from 'ethers'; import { RequesterAuthorizerWithErc721__factory as RequesterAuthorizerWithErc721Factory, MockErc721__factory as MockErc721Factory, @@ -36,7 +35,6 @@ const AirnodeRrpDryRunAddresses: { [chainId: string]: string } = references.Airn const AccessControlRegistryAddresses: { [chainId: string]: string } = references.AccessControlRegistry; const RequesterAuthorizerWithAirnodeAddresses: { [chainId: string]: string } = references.RequesterAuthorizerWithAirnode; -const networks: { [chainId: string]: ethers.providers.Network } = references.networks; const PROTOCOL_IDS = { RRP: '1', @@ -72,7 +70,6 @@ export { RequesterAuthorizerWithErc721Factory, mocks, authorizers, - networks, references, PROTOCOL_IDS, erc721Mocks, diff --git a/packages/airnode-protocol/test/authorizers/RequesterAuthorizerWithAirnode.sol.js b/packages/airnode-protocol/test/authorizers/RequesterAuthorizerWithAirnode.sol.js index 65c5efbef8..a7fec24520 100644 --- a/packages/airnode-protocol/test/authorizers/RequesterAuthorizerWithAirnode.sol.js +++ b/packages/airnode-protocol/test/authorizers/RequesterAuthorizerWithAirnode.sol.js @@ -45,9 +45,8 @@ describe('RequesterAuthorizerWithAirnode', function () { .initializeRoleAndGrantToSender(airnodeRootRole, requesterAuthorizerWithAirnodeAdminRoleDescription, { gasLimit: 1000000, }); - whitelistExpirationExtenderRole = await requesterAuthorizerWithAirnode.deriveWhitelistExpirationExtenderRole( - airnodeAddress - ); + whitelistExpirationExtenderRole = + await requesterAuthorizerWithAirnode.deriveWhitelistExpirationExtenderRole(airnodeAddress); await accessControlRegistry .connect(airnodeWallet) .initializeRoleAndGrantToSender( @@ -58,9 +57,8 @@ describe('RequesterAuthorizerWithAirnode', function () { await accessControlRegistry .connect(airnodeWallet) .grantRole(whitelistExpirationExtenderRole, roles.whitelistExpirationExtender.address, { gasLimit: 1000000 }); - whitelistExpirationSetterRole = await requesterAuthorizerWithAirnode.deriveWhitelistExpirationSetterRole( - airnodeAddress - ); + whitelistExpirationSetterRole = + await requesterAuthorizerWithAirnode.deriveWhitelistExpirationSetterRole(airnodeAddress); await accessControlRegistry .connect(airnodeWallet) .initializeRoleAndGrantToSender( diff --git a/packages/airnode-utilities/CHANGELOG.md b/packages/airnode-utilities/CHANGELOG.md index 85f16750cc..a07525853d 100644 --- a/packages/airnode-utilities/CHANGELOG.md +++ b/packages/airnode-utilities/CHANGELOG.md @@ -1,5 +1,14 @@ # @api3/airnode-utilities +## 0.13.0 + +### Patch Changes + +- [#1825](https://github.com/api3dao/airnode/pull/1825) [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3) Thanks [@renovate](https://github.com/apps/renovate)! - Apply prettier v3 formatting + +- Updated dependencies [[`1da62631`](https://github.com/api3dao/airnode/commit/1da62631905cf4b49266f248c8c385b5106d4c4d), [`cefc5e4a`](https://github.com/api3dao/airnode/commit/cefc5e4abcc0f10a9b0b84b9bf55af2f34ffe1bd)]: + - @api3/airnode-validator@0.13.0 + ## 0.12.0 ### Minor Changes diff --git a/packages/airnode-utilities/package.json b/packages/airnode-utilities/package.json index e8d0d16bd7..74e43b0d31 100644 --- a/packages/airnode-utilities/package.json +++ b/packages/airnode-utilities/package.json @@ -1,7 +1,7 @@ { "name": "@api3/airnode-utilities", "license": "MIT", - "version": "0.12.0", + "version": "0.13.0", "private": false, "description": "General utilities to support Airnode packages", "files": [ @@ -18,19 +18,19 @@ "types": "dist/index", "main": "dist/index.js", "dependencies": { - "@api3/airnode-validator": "^0.12.0", + "@api3/airnode-validator": "^0.13.0", "@api3/promise-utils": "^0.4.0", "date-fns": "^2.30.0", "ethers": "^5.7.2" }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.2.3", - "@types/jest": "^29.5.2", - "@types/node": "^18.16.19", + "@types/jest": "^29.5.6", + "@types/node": "^18.18.7", "hardhat": "^2.14.1", - "jest": "^29.6.0", - "rimraf": "^5.0.1", + "jest": "^29.7.0", + "rimraf": "^5.0.5", "ts-node": "^10.9.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } } diff --git a/packages/airnode-utilities/src/evm/gas-prices/gas-oracle.test.ts b/packages/airnode-utilities/src/evm/gas-prices/gas-oracle.test.ts index e0601fd4ec..e6173a4187 100644 --- a/packages/airnode-utilities/src/evm/gas-prices/gas-oracle.test.ts +++ b/packages/airnode-utilities/src/evm/gas-prices/gas-oracle.test.ts @@ -281,7 +281,7 @@ describe('Gas oracle', () => { () => ({ baseFeePerGas: ethers.BigNumber.from(18), - } as any) + }) as any ); const [_logs, gasTarget] = await gasOracle.getGasPrice(provider, { @@ -304,7 +304,7 @@ describe('Gas oracle', () => { () => ({ baseFeePerGas: ethers.BigNumber.from(18), - } as any) + }) as any ); jest .spyOn(ethers.providers.StaticJsonRpcProvider.prototype, 'getGasPrice') diff --git a/packages/airnode-validator/CHANGELOG.md b/packages/airnode-validator/CHANGELOG.md index 45a7bad07a..90e1d5eb05 100644 --- a/packages/airnode-validator/CHANGELOG.md +++ b/packages/airnode-validator/CHANGELOG.md @@ -1,5 +1,18 @@ # @api3/airnode-validator +## 0.13.0 + +### Minor Changes + +- [#1888](https://github.com/api3dao/airnode/pull/1888) [`1da62631`](https://github.com/api3dao/airnode/commit/1da62631905cf4b49266f248c8c385b5106d4c4d) Thanks [@dcroote](https://github.com/dcroote)! - Bump OIS to v2.2.0 and make operationParameter optional within endpoint parameters + +### Patch Changes + +- [#1893](https://github.com/api3dao/airnode/pull/1893) [`cefc5e4a`](https://github.com/api3dao/airnode/commit/cefc5e4abcc0f10a9b0b84b9bf55af2f34ffe1bd) Thanks [@dcroote](https://github.com/dcroote)! - Bump ois to v2.2.1 + +- Updated dependencies [[`87cee037`](https://github.com/api3dao/airnode/commit/87cee0372afc60acb141ad308d3664172f3cbdb6), [`d2e5a04b`](https://github.com/api3dao/airnode/commit/d2e5a04bf6e88de1888f044dfb171344171ba0ea), [`1d7e4b2f`](https://github.com/api3dao/airnode/commit/1d7e4b2fe4467cee05a6d5f4b34b772d377337df), [`b447fcc5`](https://github.com/api3dao/airnode/commit/b447fcc5d82f63c9393e2ef5651cedf66809a4a3)]: + - @api3/airnode-protocol@0.13.0 + ## 0.12.0 ### Minor Changes diff --git a/packages/airnode-validator/package.json b/packages/airnode-validator/package.json index 546b90f91f..7a17d4de55 100644 --- a/packages/airnode-validator/package.json +++ b/packages/airnode-validator/package.json @@ -1,7 +1,7 @@ { "name": "@api3/airnode-validator", "license": "MIT", - "version": "0.12.0", + "version": "0.13.0", "private": false, "main": "./dist/src/index.js", "bin": { @@ -21,22 +21,22 @@ "test:e2e:update-snapshot": "yarn test:e2e --updateSnapshot" }, "dependencies": { - "@api3/airnode-protocol": "^0.12.0", - "@api3/ois": "2.1.0", + "@api3/airnode-protocol": "^0.13.0", + "@api3/ois": "2.3.1", "@api3/promise-utils": "^0.4.0", "dotenv": "^16.3.1", "ethers": "^5.7.2", "lodash": "^4.17.21", "ora": "^5.4.1", "yargs": "^17.7.2", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { - "@types/yargs": "^17.0.24", - "jest": "^29.6.0", - "rimraf": "^5.0.1", + "@types/yargs": "^17.0.29", + "jest": "^29.7.0", + "rimraf": "^5.0.5", "ts-jest": "^29.1.1", "ts-node": "^10.9.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } } diff --git a/packages/airnode-validator/src/config/config.test.ts b/packages/airnode-validator/src/config/config.test.ts index 06106e089e..aa1b605999 100644 --- a/packages/airnode-validator/src/config/config.test.ts +++ b/packages/airnode-validator/src/config/config.test.ts @@ -874,7 +874,7 @@ describe('ensureCrossChainRequesterAuthorizerWithErc721', () => { const { contracts, ...crossChainWithoutAddress } = crossChainRequesterAuthorizerWithErc721; it('adds the default RequesterAuthorizerWithErc721 contract address for the given chain if the chain has a deployment', () => { - const idWithDeployment = '1'; + const idWithDeployment = '11155111'; const crossChainWithDeployment = { ...crossChainWithoutAddress, chainId: idWithDeployment, @@ -892,6 +892,8 @@ describe('ensureCrossChainRequesterAuthorizerWithErc721', () => { chainId: idWithoutDeployment, }; + expect(Object.keys(RequesterAuthorizerWithErc721Addresses)).not.toContain(idWithoutDeployment); + expect(() => crossChainRequesterAuthorizersWithErc721Schema.parse(crossChainWithoutDeployment)).toThrow( new ZodError([ { @@ -915,7 +917,7 @@ describe('ensureRequesterAuthorizerWithErc721', () => { .RequesterAuthorizerWithErc721; it('adds the default RequesterAuthorizerWithErc721 contract address for the given chain if the chain has a deployment', () => { - const idWithDeployment = '1'; + const idWithDeployment = '11155111'; const configWithDeployment = { ...chainWithoutRequesterAuthorizerWithErc721Address, id: idWithDeployment, @@ -933,6 +935,8 @@ describe('ensureRequesterAuthorizerWithErc721', () => { id: idWithoutDeployment, }; + expect(Object.keys(RequesterAuthorizerWithErc721Addresses)).not.toContain(idWithoutDeployment); + expect(() => chainConfigSchema.parse(crossChainWithoutDeployment)).toThrow( new ZodError([ { diff --git a/packages/airnode-validator/test/fixtures/config.valid.json b/packages/airnode-validator/test/fixtures/config.valid.json index 7bc2cd2838..dbbe451078 100644 --- a/packages/airnode-validator/test/fixtures/config.valid.json +++ b/packages/airnode-validator/test/fixtures/config.valid.json @@ -84,7 +84,7 @@ }, "logFormat": "plain", "logLevel": "INFO", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -102,7 +102,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-validator/test/fixtures/interpolated-config.valid.json b/packages/airnode-validator/test/fixtures/interpolated-config.valid.json index af937b898a..517d1e7c1d 100644 --- a/packages/airnode-validator/test/fixtures/interpolated-config.valid.json +++ b/packages/airnode-validator/test/fixtures/interpolated-config.valid.json @@ -88,7 +88,7 @@ }, "logFormat": "plain", "logLevel": "INFO", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "stage": "dev" }, "triggers": { @@ -106,7 +106,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-validator/test/fixtures/invalid-secret-name/config.json b/packages/airnode-validator/test/fixtures/invalid-secret-name/config.json index 0f006085d6..d84c19e70a 100644 --- a/packages/airnode-validator/test/fixtures/invalid-secret-name/config.json +++ b/packages/airnode-validator/test/fixtures/invalid-secret-name/config.json @@ -72,7 +72,7 @@ "templates": [], "ois": [ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "title": "CoinGecko basic request", "version": "1.0.0", "apiSpecifications": { diff --git a/packages/airnode-validator/test/fixtures/ois.json b/packages/airnode-validator/test/fixtures/ois.json index 3631bb8951..664de169d6 100644 --- a/packages/airnode-validator/test/fixtures/ois.json +++ b/packages/airnode-validator/test/fixtures/ois.json @@ -1,5 +1,5 @@ { - "oisFormat": "2.1.0", + "oisFormat": "2.3.1", "version": "1.2.3", "title": "coinlayer", "apiSpecifications": { diff --git a/packages/airnode-validator/test/fixtures/receipt.valid.json b/packages/airnode-validator/test/fixtures/receipt.valid.json index 560b7026a9..106111167d 100644 --- a/packages/airnode-validator/test/fixtures/receipt.valid.json +++ b/packages/airnode-validator/test/fixtures/receipt.valid.json @@ -11,7 +11,7 @@ "disableConcurrencyReservations": false }, "stage": "starter-example", - "nodeVersion": "0.12.0", + "nodeVersion": "0.13.0", "timestamp": "2022-05-18T06:37:35.507Z" }, "success": true diff --git a/scripts/test-release.ts b/scripts/test-release.ts new file mode 100644 index 0000000000..54285231b1 --- /dev/null +++ b/scripts/test-release.ts @@ -0,0 +1,222 @@ +/** + * This script facilitates testing of Airnode releases and snapshot releases. + * It covers the following: + * - Testing npm packages that have a help command to catch broken packaging + * - Validating config.json and secrets.env using the npm validator package + * - Testing the generate-mnemonic command of the npm admin package + * - Pulling the docker images + * - Deploying Airnode to a cloud provider + * - Making a blockchain request + * - Making a HTTP gateway request + * - Making a HTTP signed data gateway request + * - Listing deployed Airnodes + * - Removing the Airnode deployment + */ +import { spawnSync } from 'child_process'; +import { existsSync, readFileSync } from 'fs'; +import axios from 'axios'; +import prompts from 'prompts'; + +/* eslint-disable no-console */ + +// spawnSync with 'pipe' is sufficient for npx and many yarn commands, but others like deploy-airnode +// will error with 'the input device is not a TTY' and therefore need inherit +type spawnSyncStdIo = 'pipe' | 'inherit'; + +const executeCommandSync = (command: string, spawnSyncStdIo: spawnSyncStdIo = 'pipe', outputFile = '') => { + console.info(`Running command: ${command}`); + const redirect = outputFile ? `> ${outputFile} 2>&1` : ''; + const result = spawnSync(command + redirect, { + stdio: spawnSyncStdIo, + shell: true, + }); + + if (result.error) { + throw result.error; + } + + if (result.status !== 0) { + throw new Error( + [ + `Command failed with non-zero status code: ${result.status}`, + `Stderr: ${result.stderr?.toString().trim()}`, + `Stdout: ${result.stdout?.toString().trim()}`, + ].join('\n') + ); + } +}; + +const promptKeyPress = async (message: string) => { + console.log(message); + await prompts({ + type: 'confirm', + name: 'continue', + message: 'Press enter to continue...', + initial: true, + }); +}; + +export const extractGatewayUrls = (consoleOutput: string) => { + const httpRegex = /HTTP gateway URL: (https:\/\/[^\s]+)/; + const httpMatches = consoleOutput.match(httpRegex); + if (!httpMatches) { + throw new Error('Could not extract the HTTP gateway URL from console output'); + } + const signedRegex = /HTTP signed data gateway URL: (https:\/\/[^\s]+)/; + const signedMatches = consoleOutput.match(signedRegex); + if (!signedMatches) { + throw new Error('Could not extract the HTTP signed data gateway URL from console output'); + } + return { + httpGatewayUrl: httpMatches[1], + signedHttpGatewayUrl: signedMatches[1], + }; +}; + +const main = async () => { + const response = await prompts([ + { + type: 'text', + name: 'releaseVersion', + message: 'Enter the release version e.g., "0.13.0" or "snapshot-v0.13.0"', + }, + { + type: 'text', + name: 'airnodePath', + message: 'Enter the full path to the Airnode root directory:', + initial: process.cwd(), + }, + ]); + + const { releaseVersion, airnodePath } = response; + // snapshot docker images have a '-dev' suffix, release images do not + const dockerImgSuffix = releaseVersion.includes('snapshot') ? '-dev' : ''; + const airnodeExamplesPath = `${airnodePath}/packages/airnode-examples`; + const npmPackages = ['admin', 'deployer', 'validator']; + const dockerImgs = ['deployer', 'admin', 'client']; + + // Test npm packages that have a help command to catch broken packaging + for (const pkg of npmPackages) { + const NAME = `@api3/airnode-${pkg}@${releaseVersion}`; + executeCommandSync(`npx -y ${NAME} --help`); + } + + executeCommandSync( + `npx -y @api3/airnode-validator@${releaseVersion} --config "${airnodePath}/packages/airnode-validator/test/fixtures/config.valid.json" --secrets "${airnodePath}/packages/airnode-validator/test/fixtures/secrets.valid.env"` + ); + + executeCommandSync(`npx -y @api3/airnode-admin@${releaseVersion} generate-mnemonic`); + + for (const image of dockerImgs) { + executeCommandSync(`docker pull api3/airnode-${image}${dockerImgSuffix}:${releaseVersion}`); + } + + process.chdir(airnodeExamplesPath); + + const confirmIntegration = await prompts({ + type: 'confirm', + name: 'bool', + message: + "Do you want to rerun 'yarn choose-integration'? (make sure 'coingecko-http-gateways' is set as the integration)", + initial: true, + }); + + if (confirmIntegration.bool) { + executeCommandSync('yarn choose-integration', 'inherit'); + } + + const integrationInfo = JSON.parse(readFileSync(`${airnodeExamplesPath}/integration-info.json`).toString()); + const cloudProvider = integrationInfo.airnodeType; + const integration = integrationInfo.integration; + + if (cloudProvider === 'aws' && !existsSync(`${airnodeExamplesPath}/integrations/${integration}/aws.env`)) { + executeCommandSync('yarn create-aws-secrets'); + } + if (cloudProvider === 'gcp' && !existsSync(`${airnodeExamplesPath}/integrations/${integration}/gcp.json`)) { + console.error(`Missing ${airnodeExamplesPath}/integrations/${integration}/gcp.json`); + console.error('See the airnode-examples README for instructions on how to generate it.'); + process.exit(1); + } + + const deployAirnode = await prompts({ + type: 'confirm', + name: 'bool', + message: 'Do you want to deploy Airnode? (no = skip deployment, but continue script)', + initial: true, + }); + // Redirect output to a file, which is then read to extract the gateway URLs. This is necessary + // because 'inherit' doesn't allow for stdout to be captured, unlike 'pipe' + const deploymentOutputFilename = 'test-release-deployment.log'; + if (deployAirnode.bool) { + // Running create-airnode-config requires a new deployment, hence they're grouped together + executeCommandSync('yarn create-airnode-config'); + executeCommandSync('yarn create-airnode-secrets'); + executeCommandSync( + `yarn deploy-airnode api3/airnode-deployer${dockerImgSuffix}:${releaseVersion}`, + 'inherit', + deploymentOutputFilename + ); + } + const deploymentOutput = readFileSync(`${airnodeExamplesPath}/${deploymentOutputFilename}`).toString(); + const gatewayUrls = extractGatewayUrls(deploymentOutput); + + executeCommandSync('yarn deploy-requester'); + executeCommandSync('yarn derive-and-fund-sponsor-wallet'); + executeCommandSync('yarn sponsor-requester'); + // Wait for 30 seconds as sometimes sponsorship will not be recognized immediately + console.log('Waiting for 30 seconds before making a request...'); + await new Promise((resolve) => setTimeout(resolve, 30000)); + executeCommandSync('yarn make-request'); + executeCommandSync('yarn make-withdrawal-request'); + + const httpConfig = { + method: 'post', + // triggers.http[0].endpointId from coingecko-http-gateways config.json + url: `${gatewayUrls.httpGatewayUrl}/0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4`, + headers: { + 'Content-Type': 'application/json', + }, + data: JSON.stringify({ + parameters: { + coinId: 'ethereum', + _path: 'market_data.current_price.usd', + }, + }), + }; + + console.log('Making HTTP request...'); + const httpResponse = await axios.request(httpConfig); + console.log(`HTTP gateway price value: ${httpResponse.data.values}`); + + const signedConfig = { + method: 'post', + maxBodyLength: Infinity, + // triggers.httpSignedData[0].endpointId from coingecko-http-gateways config.json + url: `${gatewayUrls.signedHttpGatewayUrl}/0xfb87102cdabadf905321521ba0b3cbf74ad09c5d400ac2eccdbef8d6143e78c4`, + headers: { + 'Content-Type': 'application/json', + }, + data: JSON.stringify({ + encodedParameters: + // From coingecko-http-gateways integration README for encoded 'ethereum' coinId + '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000657468657265756d000000000000000000000000000000000000000000000000', + }), + }; + + console.log('Making HTTP signed gateway request...'); + const signedResponse = await axios.request(signedConfig); + console.log(`Signed http gateway JSON response: ${JSON.stringify(signedResponse.data)}`); + + executeCommandSync( + `docker run -it --rm -v "${airnodeExamplesPath}/integrations/${integration}:/app/config" ` + + `api3/airnode-deployer${dockerImgSuffix}:${releaseVersion} list`, + 'inherit' + ); + + await promptKeyPress('Ready to remove the Airnode deployment?'); + executeCommandSync(`yarn remove-airnode api3/airnode-deployer${dockerImgSuffix}:${releaseVersion}`, 'inherit'); + + console.log('Testing success.'); +}; + +main(); diff --git a/scripts/update-config-fixtures.ts b/scripts/update-config-fixtures.ts index a8ed97a735..60e84e49c6 100644 --- a/scripts/update-config-fixtures.ts +++ b/scripts/update-config-fixtures.ts @@ -6,7 +6,7 @@ import { version as packageVersion } from '../packages/airnode-node/package.json const configPatterns = ['./packages/**/*config.example.json', './packages/**/*config.valid.json']; configPatterns.forEach((pattern) => { const exampleConfigs = fg.sync(pattern, { ignore: ['**/node_modules'] }); - exampleConfigs.forEach((f) => { + exampleConfigs.forEach(async (f) => { const config = JSON.parse(readFileSync(f, 'utf-8')); // eslint-disable-next-line functional/immutable-data @@ -14,7 +14,8 @@ configPatterns.forEach((pattern) => { // eslint-disable-next-line no-console console.log(`Updating "${f}" to version ${packageVersion}`); - writeFileSync(f, format(JSON.stringify(config, null, 2), { parser: 'json', printWidth: 120 })); + const formattedConfig = await format(JSON.stringify(config, null, 2), { parser: 'json', printWidth: 120 }); + writeFileSync(f, formattedConfig); }); }); diff --git a/scripts/update-ois-version.ts b/scripts/update-ois-version.ts index 627c6a6e90..1b116e07e2 100644 --- a/scripts/update-ois-version.ts +++ b/scripts/update-ois-version.ts @@ -19,20 +19,21 @@ if (versions.length > 1) { if (versions.length === 0) { throw new Error(`No version of @api3/ois found in packages`); } -const packageVersion = versions[0]; +const packageVersion = versions[0].replace('^', ''); const oisJsonPatterns = ['./packages/**/*config*.json', './packages/**/ois.json']; oisJsonPatterns.forEach((pattern) => { // ignore any node_modules subfolders const oisJson = fg.sync(pattern, { ignore: ['**/node_modules', '**/tsconfig.json'] }); - oisJson.forEach((f) => { + oisJson.forEach(async (f) => { // There can be multiple instances of `oisFormat` within config.json as the `ois` field value is an array. // Therefore, use a regex instead of parsing the JSON and updating `oisFormat` field(s). const ois = readFileSync(f, 'utf-8').replace(/"oisFormat": ".*"/, `"oisFormat": "${packageVersion}"`); // eslint-disable-next-line no-console console.log(`Updating "${f}" to oisFormat version ${packageVersion}`); - writeFileSync(f, format(ois, { parser: 'json', printWidth: 120 })); + const formattedConfig = await format(ois, { parser: 'json', printWidth: 120 }); + writeFileSync(f, formattedConfig); }); }); diff --git a/yarn.lock b/yarn.lock index c81888b409..e958c36c74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== +"@adraffy/ens-normalize@1.10.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" + integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== + "@ampproject/remapping@^2.2.0": version "2.2.1" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" @@ -15,27 +20,65 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@api3/airnode-protocol-v1@^2.8.0": - version "2.8.0" - resolved "https://registry.yarnpkg.com/@api3/airnode-protocol-v1/-/airnode-protocol-v1-2.8.0.tgz#19a755bf0dfb127edd362282b09b9ff51409e626" - integrity sha512-QmDaFvD8U3CYuYqpKP7au7htr1fIW5s6YzoAfduDqh6z6jqFWUHd4wd3m0BYu715SZpu5xSa0lsYpfnPhxHpIg== +"@api3/airnode-protocol-v1@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@api3/airnode-protocol-v1/-/airnode-protocol-v1-3.1.0.tgz#b4cfe0a0321f51326e959d7201a8094454fc2cbc" + integrity sha512-3XOYdQqQPWXC2xSz1cCnk6kzkeugE6NdxgU25C43dzkJStvY+jALyxmS9SBtsUCaq4KA7hYVxci5gkDi7rZbAQ== dependencies: "@openzeppelin/contracts" "4.8.2" -"@api3/chains@^3.3.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/@api3/chains/-/chains-3.3.0.tgz#a1b370f7b57907a5cd86f56a3207c424a9cb350d" - integrity sha512-/INfCDsOrxn/mTxkl3NPP0IukNIhAzpw9fmB4R+0GOJJqC6x+nBvApFzCqG7LeBRhdVIMUoIcbvxG7aAW4eF0Q== +"@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: - zod "^3.21.4" + viem "^2.0.6" + zod "^3.22.4" -"@api3/ois@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@api3/ois/-/ois-2.1.0.tgz#71a6b9e67a72fa972527e578f2a81a6a3e7b6863" - integrity sha512-KcDzCNhC1z4XSrpz5G6XsvgUdJhTEtDwJLJX6VP8QNhIk6FWKgCqYUHuJ4PhOoSkMGUPPVu5jYqGbZj4q8ymEA== +"@api3/commons@^0.5.0": + version "0.5.0" + resolved "https://registry.npmjs.org/@api3/commons/-/commons-0.5.0.tgz#d9ff9aba3a2da8cd7b678371550881e008c43a1c" + integrity sha512-PqSukqnAGQORuGTSLaQiVuxUtU5RBNOhm5GEnX0fhROhoKyX11E5EJuuQqYwIG4LsBkhVGNJuR7PhnUs6VmwrA== + dependencies: + "@api3/ois" "^2.3.0" + "@api3/promise-utils" "^0.4.0" + "@typescript-eslint/eslint-plugin" "^6.2.1" + "@typescript-eslint/parser" "^6.2.1" + eslint-config-next "^13.1.6" + eslint-plugin-check-file "^2.6.2" + eslint-plugin-cypress "^2.14.0" + eslint-plugin-deprecation "^2.0.0" + eslint-plugin-functional "^6.0.0" + eslint-plugin-import "^2.28.1" + eslint-plugin-jest "^27.4.2" + eslint-plugin-jest-formatting "^3.1.0" + eslint-plugin-lodash "^7.4.0" + eslint-plugin-no-only-tests "^3.1.0" + eslint-plugin-promise "^6.1.1" + eslint-plugin-react "^7.32.1" + eslint-plugin-react-hooks "^4.6.0" + eslint-plugin-unicorn "^48.0.1" + ethers "^5.7.2" + lodash "^4.17.21" + winston "^3.10.0" + winston-console-format "^1.0.8" + zod "^3.22.4" + +"@api3/ois@2.3.1": + version "2.3.1" + resolved "https://registry.npmjs.org/@api3/ois/-/ois-2.3.1.tgz#de80dc1b404f094be9049d2a8fdc0362cdfd7dce" + integrity sha512-7TmgEiJn3TrqV2BZGh4fKTF4qX7Q/dyGdQh9L6gj4dHBmoKzfK0eDbwjWR+RokYrd9k4E4whGNxEnzdZr3ubSA== + dependencies: + lodash "^4.17.21" + zod "^3.22.4" + +"@api3/ois@^2.3.0": + version "2.3.0" + resolved "https://registry.npmjs.org/@api3/ois/-/ois-2.3.0.tgz#f5407eab380396c70031a82b4d9e188200082474" + integrity sha512-B/F9sirQLBZNGClnpK/U585/gqYvjEHNKR5Xgc92LTvPe6F8w9RSW3JNZo4qAc+7Tzly9xr6kmoWQJsgnwD9iQ== dependencies: lodash "^4.17.21" - zod "^3.21.4" + zod "^3.22.4" "@api3/promise-utils@^0.4.0": version "0.4.0" @@ -119,464 +162,491 @@ "@aws-sdk/util-utf8-browser" "^3.0.0" tslib "^1.11.1" -"@aws-sdk/client-lambda@^3.382.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-lambda/-/client-lambda-3.391.0.tgz#88e2d9eee31bf02fe0b7482431a1e8d37d7ca864" - integrity sha512-NulxmBFKIJ1l6GeKD+kYzQioi3HsIRKCWRzosNxtyhCwPRqFp9dzJ6S4024hEyeDN2q3OYknMz5oOQnQn2pvTg== +"@aws-sdk/client-lambda@^3.418.0": + version "3.421.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-lambda/-/client-lambda-3.421.0.tgz#cf6736abdd4ceffae213490f1310c04b10360fe0" + integrity sha512-cMk7JeQlyoeIxabVsZXr3rwIfgxSL4kJpoDgFu8q+hnifOdgD8gP6AhMfYu+NMroXjUntXu+ZJbo5eBTn80OtQ== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.391.0" - "@aws-sdk/credential-provider-node" "3.391.0" - "@aws-sdk/middleware-host-header" "3.391.0" - "@aws-sdk/middleware-logger" "3.391.0" - "@aws-sdk/middleware-recursion-detection" "3.391.0" - "@aws-sdk/middleware-signing" "3.391.0" - "@aws-sdk/middleware-user-agent" "3.391.0" - "@aws-sdk/types" "3.391.0" - "@aws-sdk/util-endpoints" "3.391.0" - "@aws-sdk/util-user-agent-browser" "3.391.0" - "@aws-sdk/util-user-agent-node" "3.391.0" - "@smithy/config-resolver" "^2.0.3" - "@smithy/eventstream-serde-browser" "^2.0.3" - "@smithy/eventstream-serde-config-resolver" "^2.0.3" - "@smithy/eventstream-serde-node" "^2.0.3" - "@smithy/fetch-http-handler" "^2.0.3" - "@smithy/hash-node" "^2.0.3" - "@smithy/invalid-dependency" "^2.0.3" - "@smithy/middleware-content-length" "^2.0.3" - "@smithy/middleware-endpoint" "^2.0.3" - "@smithy/middleware-retry" "^2.0.3" - "@smithy/middleware-serde" "^2.0.3" - "@smithy/middleware-stack" "^2.0.0" - "@smithy/node-config-provider" "^2.0.3" - "@smithy/node-http-handler" "^2.0.3" - "@smithy/protocol-http" "^2.0.3" - "@smithy/smithy-client" "^2.0.3" - "@smithy/types" "^2.2.0" - "@smithy/url-parser" "^2.0.3" + "@aws-sdk/client-sts" "3.421.0" + "@aws-sdk/credential-provider-node" "3.421.0" + "@aws-sdk/middleware-host-header" "3.418.0" + "@aws-sdk/middleware-logger" "3.418.0" + "@aws-sdk/middleware-recursion-detection" "3.418.0" + "@aws-sdk/middleware-signing" "3.418.0" + "@aws-sdk/middleware-user-agent" "3.418.0" + "@aws-sdk/region-config-resolver" "3.418.0" + "@aws-sdk/types" "3.418.0" + "@aws-sdk/util-endpoints" "3.418.0" + "@aws-sdk/util-user-agent-browser" "3.418.0" + "@aws-sdk/util-user-agent-node" "3.418.0" + "@smithy/config-resolver" "^2.0.10" + "@smithy/eventstream-serde-browser" "^2.0.9" + "@smithy/eventstream-serde-config-resolver" "^2.0.9" + "@smithy/eventstream-serde-node" "^2.0.9" + "@smithy/fetch-http-handler" "^2.1.5" + "@smithy/hash-node" "^2.0.9" + "@smithy/invalid-dependency" "^2.0.9" + "@smithy/middleware-content-length" "^2.0.11" + "@smithy/middleware-endpoint" "^2.0.9" + "@smithy/middleware-retry" "^2.0.12" + "@smithy/middleware-serde" "^2.0.9" + "@smithy/middleware-stack" "^2.0.2" + "@smithy/node-config-provider" "^2.0.12" + "@smithy/node-http-handler" "^2.1.5" + "@smithy/protocol-http" "^3.0.5" + "@smithy/smithy-client" "^2.1.6" + "@smithy/types" "^2.3.3" + "@smithy/url-parser" "^2.0.9" "@smithy/util-base64" "^2.0.0" "@smithy/util-body-length-browser" "^2.0.0" - "@smithy/util-body-length-node" "^2.0.0" - "@smithy/util-defaults-mode-browser" "^2.0.3" - "@smithy/util-defaults-mode-node" "^2.0.3" - "@smithy/util-retry" "^2.0.0" - "@smithy/util-stream" "^2.0.3" + "@smithy/util-body-length-node" "^2.1.0" + "@smithy/util-defaults-mode-browser" "^2.0.10" + "@smithy/util-defaults-mode-node" "^2.0.12" + "@smithy/util-retry" "^2.0.2" + "@smithy/util-stream" "^2.0.12" "@smithy/util-utf8" "^2.0.0" - "@smithy/util-waiter" "^2.0.3" + "@smithy/util-waiter" "^2.0.9" tslib "^2.5.0" -"@aws-sdk/client-s3@^3.383.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.391.0.tgz#1a9a9531c2f7e19277e1aed65ec22b983a713689" - integrity sha512-QGRcawQFYM/WtaKgr15oi2xzoqhniqp9aAGDVW+iClbOtMfXr2o79RDqPGKge+uQsmw2we0qgvphypDm7RMMgw== +"@aws-sdk/client-s3@^3.418.0": + version "3.421.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.421.0.tgz#cf0e4a5e394c55463839b405af9dc6e3271509e4" + integrity sha512-vUXTY4toeHDf5EY2kOn04Ww9vTW2IVGy4+cymFp1cz5QT7g9KKj4Okj5DMdPld2y7wjgc+J/viTWEf26By49vw== dependencies: "@aws-crypto/sha1-browser" "3.0.0" "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.391.0" - "@aws-sdk/credential-provider-node" "3.391.0" - "@aws-sdk/middleware-bucket-endpoint" "3.391.0" - "@aws-sdk/middleware-expect-continue" "3.391.0" - "@aws-sdk/middleware-flexible-checksums" "3.391.0" - "@aws-sdk/middleware-host-header" "3.391.0" - "@aws-sdk/middleware-location-constraint" "3.391.0" - "@aws-sdk/middleware-logger" "3.391.0" - "@aws-sdk/middleware-recursion-detection" "3.391.0" - "@aws-sdk/middleware-sdk-s3" "3.391.0" - "@aws-sdk/middleware-signing" "3.391.0" - "@aws-sdk/middleware-ssec" "3.391.0" - "@aws-sdk/middleware-user-agent" "3.391.0" - "@aws-sdk/signature-v4-multi-region" "3.391.0" - "@aws-sdk/types" "3.391.0" - "@aws-sdk/util-endpoints" "3.391.0" - "@aws-sdk/util-user-agent-browser" "3.391.0" - "@aws-sdk/util-user-agent-node" "3.391.0" + "@aws-sdk/client-sts" "3.421.0" + "@aws-sdk/credential-provider-node" "3.421.0" + "@aws-sdk/middleware-bucket-endpoint" "3.418.0" + "@aws-sdk/middleware-expect-continue" "3.418.0" + "@aws-sdk/middleware-flexible-checksums" "3.418.0" + "@aws-sdk/middleware-host-header" "3.418.0" + "@aws-sdk/middleware-location-constraint" "3.418.0" + "@aws-sdk/middleware-logger" "3.418.0" + "@aws-sdk/middleware-recursion-detection" "3.418.0" + "@aws-sdk/middleware-sdk-s3" "3.418.0" + "@aws-sdk/middleware-signing" "3.418.0" + "@aws-sdk/middleware-ssec" "3.418.0" + "@aws-sdk/middleware-user-agent" "3.418.0" + "@aws-sdk/region-config-resolver" "3.418.0" + "@aws-sdk/signature-v4-multi-region" "3.418.0" + "@aws-sdk/types" "3.418.0" + "@aws-sdk/util-endpoints" "3.418.0" + "@aws-sdk/util-user-agent-browser" "3.418.0" + "@aws-sdk/util-user-agent-node" "3.418.0" "@aws-sdk/xml-builder" "3.310.0" - "@smithy/config-resolver" "^2.0.3" - "@smithy/eventstream-serde-browser" "^2.0.3" - "@smithy/eventstream-serde-config-resolver" "^2.0.3" - "@smithy/eventstream-serde-node" "^2.0.3" - "@smithy/fetch-http-handler" "^2.0.3" - "@smithy/hash-blob-browser" "^2.0.3" - "@smithy/hash-node" "^2.0.3" - "@smithy/hash-stream-node" "^2.0.3" - "@smithy/invalid-dependency" "^2.0.3" - "@smithy/md5-js" "^2.0.3" - "@smithy/middleware-content-length" "^2.0.3" - "@smithy/middleware-endpoint" "^2.0.3" - "@smithy/middleware-retry" "^2.0.3" - "@smithy/middleware-serde" "^2.0.3" - "@smithy/middleware-stack" "^2.0.0" - "@smithy/node-config-provider" "^2.0.3" - "@smithy/node-http-handler" "^2.0.3" - "@smithy/protocol-http" "^2.0.3" - "@smithy/smithy-client" "^2.0.3" - "@smithy/types" "^2.2.0" - "@smithy/url-parser" "^2.0.3" + "@smithy/config-resolver" "^2.0.10" + "@smithy/eventstream-serde-browser" "^2.0.9" + "@smithy/eventstream-serde-config-resolver" "^2.0.9" + "@smithy/eventstream-serde-node" "^2.0.9" + "@smithy/fetch-http-handler" "^2.1.5" + "@smithy/hash-blob-browser" "^2.0.9" + "@smithy/hash-node" "^2.0.9" + "@smithy/hash-stream-node" "^2.0.9" + "@smithy/invalid-dependency" "^2.0.9" + "@smithy/md5-js" "^2.0.9" + "@smithy/middleware-content-length" "^2.0.11" + "@smithy/middleware-endpoint" "^2.0.9" + "@smithy/middleware-retry" "^2.0.12" + "@smithy/middleware-serde" "^2.0.9" + "@smithy/middleware-stack" "^2.0.2" + "@smithy/node-config-provider" "^2.0.12" + "@smithy/node-http-handler" "^2.1.5" + "@smithy/protocol-http" "^3.0.5" + "@smithy/smithy-client" "^2.1.6" + "@smithy/types" "^2.3.3" + "@smithy/url-parser" "^2.0.9" "@smithy/util-base64" "^2.0.0" "@smithy/util-body-length-browser" "^2.0.0" - "@smithy/util-body-length-node" "^2.0.0" - "@smithy/util-defaults-mode-browser" "^2.0.3" - "@smithy/util-defaults-mode-node" "^2.0.3" - "@smithy/util-retry" "^2.0.0" - "@smithy/util-stream" "^2.0.3" + "@smithy/util-body-length-node" "^2.1.0" + "@smithy/util-defaults-mode-browser" "^2.0.10" + "@smithy/util-defaults-mode-node" "^2.0.12" + "@smithy/util-retry" "^2.0.2" + "@smithy/util-stream" "^2.0.12" "@smithy/util-utf8" "^2.0.0" - "@smithy/util-waiter" "^2.0.3" + "@smithy/util-waiter" "^2.0.9" fast-xml-parser "4.2.5" tslib "^2.5.0" -"@aws-sdk/client-sso@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.391.0.tgz#9baf8f4871e2cd3f087839486547a91ea506189e" - integrity sha512-aT+O1CbWIWYlCtWK6g3ZaMvFNImOgFGurOEPscuedqzG5UQc1bRtRrGYShLyzcZgfXP+s0cKYJqgGeRNoWiwqA== +"@aws-sdk/client-sso@3.421.0": + version "3.421.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.421.0.tgz#794350d63bd6b327f4919460ae908a1a39585165" + integrity sha512-40CmW7K2/FZEn3CbOjbpRYeVjKu6aJQlpRHcAgEJGNoVEAnRA3YNH4H0BN2iWWITfYg3B7sIjMm5VE9fCIK1Ng== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/middleware-host-header" "3.391.0" - "@aws-sdk/middleware-logger" "3.391.0" - "@aws-sdk/middleware-recursion-detection" "3.391.0" - "@aws-sdk/middleware-user-agent" "3.391.0" - "@aws-sdk/types" "3.391.0" - "@aws-sdk/util-endpoints" "3.391.0" - "@aws-sdk/util-user-agent-browser" "3.391.0" - "@aws-sdk/util-user-agent-node" "3.391.0" - "@smithy/config-resolver" "^2.0.3" - "@smithy/fetch-http-handler" "^2.0.3" - "@smithy/hash-node" "^2.0.3" - "@smithy/invalid-dependency" "^2.0.3" - "@smithy/middleware-content-length" "^2.0.3" - "@smithy/middleware-endpoint" "^2.0.3" - "@smithy/middleware-retry" "^2.0.3" - "@smithy/middleware-serde" "^2.0.3" - "@smithy/middleware-stack" "^2.0.0" - "@smithy/node-config-provider" "^2.0.3" - "@smithy/node-http-handler" "^2.0.3" - "@smithy/protocol-http" "^2.0.3" - "@smithy/smithy-client" "^2.0.3" - "@smithy/types" "^2.2.0" - "@smithy/url-parser" "^2.0.3" + "@aws-sdk/middleware-host-header" "3.418.0" + "@aws-sdk/middleware-logger" "3.418.0" + "@aws-sdk/middleware-recursion-detection" "3.418.0" + "@aws-sdk/middleware-user-agent" "3.418.0" + "@aws-sdk/region-config-resolver" "3.418.0" + "@aws-sdk/types" "3.418.0" + "@aws-sdk/util-endpoints" "3.418.0" + "@aws-sdk/util-user-agent-browser" "3.418.0" + "@aws-sdk/util-user-agent-node" "3.418.0" + "@smithy/config-resolver" "^2.0.10" + "@smithy/fetch-http-handler" "^2.1.5" + "@smithy/hash-node" "^2.0.9" + "@smithy/invalid-dependency" "^2.0.9" + "@smithy/middleware-content-length" "^2.0.11" + "@smithy/middleware-endpoint" "^2.0.9" + "@smithy/middleware-retry" "^2.0.12" + "@smithy/middleware-serde" "^2.0.9" + "@smithy/middleware-stack" "^2.0.2" + "@smithy/node-config-provider" "^2.0.12" + "@smithy/node-http-handler" "^2.1.5" + "@smithy/protocol-http" "^3.0.5" + "@smithy/smithy-client" "^2.1.6" + "@smithy/types" "^2.3.3" + "@smithy/url-parser" "^2.0.9" "@smithy/util-base64" "^2.0.0" "@smithy/util-body-length-browser" "^2.0.0" - "@smithy/util-body-length-node" "^2.0.0" - "@smithy/util-defaults-mode-browser" "^2.0.3" - "@smithy/util-defaults-mode-node" "^2.0.3" - "@smithy/util-retry" "^2.0.0" + "@smithy/util-body-length-node" "^2.1.0" + "@smithy/util-defaults-mode-browser" "^2.0.10" + "@smithy/util-defaults-mode-node" "^2.0.12" + "@smithy/util-retry" "^2.0.2" "@smithy/util-utf8" "^2.0.0" tslib "^2.5.0" -"@aws-sdk/client-sts@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.391.0.tgz#19d33625d9ae491c8ff53eebcbda34e1685952e0" - integrity sha512-y+KmorcUx9o5O99sXVPbhGUpsLpfhzYRaYCqxArLsyzZTCO6XDXMi8vg/xtS+b703j9lWEl5GxAv2oBaEwEnhQ== +"@aws-sdk/client-sts@3.421.0": + version "3.421.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.421.0.tgz#1c7b3265be3acb609159533c24421da4e9466570" + integrity sha512-/92NOZMcdkBcvGrINk5B/l+6DGcVzYE4Ab3ME4vcY9y//u2gd0yNn5YYRSzzjVBLvhDP3u6CbTfLX2Bm4qihPw== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/credential-provider-node" "3.391.0" - "@aws-sdk/middleware-host-header" "3.391.0" - "@aws-sdk/middleware-logger" "3.391.0" - "@aws-sdk/middleware-recursion-detection" "3.391.0" - "@aws-sdk/middleware-sdk-sts" "3.391.0" - "@aws-sdk/middleware-signing" "3.391.0" - "@aws-sdk/middleware-user-agent" "3.391.0" - "@aws-sdk/types" "3.391.0" - "@aws-sdk/util-endpoints" "3.391.0" - "@aws-sdk/util-user-agent-browser" "3.391.0" - "@aws-sdk/util-user-agent-node" "3.391.0" - "@smithy/config-resolver" "^2.0.3" - "@smithy/fetch-http-handler" "^2.0.3" - "@smithy/hash-node" "^2.0.3" - "@smithy/invalid-dependency" "^2.0.3" - "@smithy/middleware-content-length" "^2.0.3" - "@smithy/middleware-endpoint" "^2.0.3" - "@smithy/middleware-retry" "^2.0.3" - "@smithy/middleware-serde" "^2.0.3" - "@smithy/middleware-stack" "^2.0.0" - "@smithy/node-config-provider" "^2.0.3" - "@smithy/node-http-handler" "^2.0.3" - "@smithy/protocol-http" "^2.0.3" - "@smithy/smithy-client" "^2.0.3" - "@smithy/types" "^2.2.0" - "@smithy/url-parser" "^2.0.3" + "@aws-sdk/credential-provider-node" "3.421.0" + "@aws-sdk/middleware-host-header" "3.418.0" + "@aws-sdk/middleware-logger" "3.418.0" + "@aws-sdk/middleware-recursion-detection" "3.418.0" + "@aws-sdk/middleware-sdk-sts" "3.418.0" + "@aws-sdk/middleware-signing" "3.418.0" + "@aws-sdk/middleware-user-agent" "3.418.0" + "@aws-sdk/region-config-resolver" "3.418.0" + "@aws-sdk/types" "3.418.0" + "@aws-sdk/util-endpoints" "3.418.0" + "@aws-sdk/util-user-agent-browser" "3.418.0" + "@aws-sdk/util-user-agent-node" "3.418.0" + "@smithy/config-resolver" "^2.0.10" + "@smithy/fetch-http-handler" "^2.1.5" + "@smithy/hash-node" "^2.0.9" + "@smithy/invalid-dependency" "^2.0.9" + "@smithy/middleware-content-length" "^2.0.11" + "@smithy/middleware-endpoint" "^2.0.9" + "@smithy/middleware-retry" "^2.0.12" + "@smithy/middleware-serde" "^2.0.9" + "@smithy/middleware-stack" "^2.0.2" + "@smithy/node-config-provider" "^2.0.12" + "@smithy/node-http-handler" "^2.1.5" + "@smithy/protocol-http" "^3.0.5" + "@smithy/smithy-client" "^2.1.6" + "@smithy/types" "^2.3.3" + "@smithy/url-parser" "^2.0.9" "@smithy/util-base64" "^2.0.0" "@smithy/util-body-length-browser" "^2.0.0" - "@smithy/util-body-length-node" "^2.0.0" - "@smithy/util-defaults-mode-browser" "^2.0.3" - "@smithy/util-defaults-mode-node" "^2.0.3" - "@smithy/util-retry" "^2.0.0" + "@smithy/util-body-length-node" "^2.1.0" + "@smithy/util-defaults-mode-browser" "^2.0.10" + "@smithy/util-defaults-mode-node" "^2.0.12" + "@smithy/util-retry" "^2.0.2" "@smithy/util-utf8" "^2.0.0" fast-xml-parser "4.2.5" tslib "^2.5.0" -"@aws-sdk/credential-provider-env@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.391.0.tgz#95ee11d77572809f4d88b3e219b9685625612d66" - integrity sha512-mAzICedcg4bfL0mM5O6QTd9mQ331NLse1DMr6XL21ZZiLB48ej19L7AGV2xq5QwVbqKU3IVv1myRyhvpDM9jMg== +"@aws-sdk/credential-provider-env@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.418.0.tgz#7b14169350d9c14c9f656da06edf46f40a224ed2" + integrity sha512-e74sS+x63EZUBO+HaI8zor886YdtmULzwKdctsZp5/37Xho1CVUNtEC+fYa69nigBD9afoiH33I4JggaHgrekQ== dependencies: - "@aws-sdk/types" "3.391.0" + "@aws-sdk/types" "3.418.0" "@smithy/property-provider" "^2.0.0" - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/credential-provider-ini@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.391.0.tgz#fa18423b01bf4c2f2fdc6d9b6fdb6764dca4f2f0" - integrity sha512-DJZmbmRMqNSfSV7UF8eBVhADz16KAMCTxnFuvgioHHfYUTZQEhCxRHI8jJqYWxhLTriS7AuTBIWr+1AIbwsCTA== - dependencies: - "@aws-sdk/credential-provider-env" "3.391.0" - "@aws-sdk/credential-provider-process" "3.391.0" - "@aws-sdk/credential-provider-sso" "3.391.0" - "@aws-sdk/credential-provider-web-identity" "3.391.0" - "@aws-sdk/types" "3.391.0" +"@aws-sdk/credential-provider-ini@3.421.0": + version "3.421.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.421.0.tgz#b58f8fd095c4389926d0e53ed2b775b184d03ec2" + integrity sha512-J5yH/gkpAk6FMeH5F9u5Nr6oG+97tj1kkn5q49g3XMbtWw7GiynadxdtoRBCeIg1C7o2LOQx4B1AnhNhIw1z/g== + dependencies: + "@aws-sdk/credential-provider-env" "3.418.0" + "@aws-sdk/credential-provider-process" "3.418.0" + "@aws-sdk/credential-provider-sso" "3.421.0" + "@aws-sdk/credential-provider-web-identity" "3.418.0" + "@aws-sdk/types" "3.418.0" "@smithy/credential-provider-imds" "^2.0.0" "@smithy/property-provider" "^2.0.0" - "@smithy/shared-ini-file-loader" "^2.0.0" - "@smithy/types" "^2.2.0" + "@smithy/shared-ini-file-loader" "^2.0.6" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/credential-provider-node@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.391.0.tgz#4f88dadb80aa4428378df0b23fb1dbb7c3e5c109" - integrity sha512-LXHQwsTw4WBwRzD9swu8254Hao5MoIaGXIzbhX4EQ84dtOkKYbwiY4pDpLfcHcw3B1lFKkVclMze8WAs4EdEww== - dependencies: - "@aws-sdk/credential-provider-env" "3.391.0" - "@aws-sdk/credential-provider-ini" "3.391.0" - "@aws-sdk/credential-provider-process" "3.391.0" - "@aws-sdk/credential-provider-sso" "3.391.0" - "@aws-sdk/credential-provider-web-identity" "3.391.0" - "@aws-sdk/types" "3.391.0" +"@aws-sdk/credential-provider-node@3.421.0": + version "3.421.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.421.0.tgz#3d1793ee47d0335532eb01a23cbb7d5320dd3056" + integrity sha512-g1dvdvfDj0u8B/gOsHR3o1arP4O4QE/dFm2IJBYr/eUdKISMUgbQULWtg4zdtAf0Oz4xN0723i7fpXAF1gTnRA== + dependencies: + "@aws-sdk/credential-provider-env" "3.418.0" + "@aws-sdk/credential-provider-ini" "3.421.0" + "@aws-sdk/credential-provider-process" "3.418.0" + "@aws-sdk/credential-provider-sso" "3.421.0" + "@aws-sdk/credential-provider-web-identity" "3.418.0" + "@aws-sdk/types" "3.418.0" "@smithy/credential-provider-imds" "^2.0.0" "@smithy/property-provider" "^2.0.0" - "@smithy/shared-ini-file-loader" "^2.0.0" - "@smithy/types" "^2.2.0" + "@smithy/shared-ini-file-loader" "^2.0.6" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/credential-provider-process@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.391.0.tgz#7f008fa719680dfeab35d77fa6787b7b31b62143" - integrity sha512-KMlzPlBI+hBmXDo+EoFZdLgCVRkRa9B9iEE6x0+hQQ6g9bW6HI7cDRVdceR1ZoPasSaNAZ9QOXMTIBxTpn0sPQ== +"@aws-sdk/credential-provider-process@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.418.0.tgz#1cb6d816bd471db3f9724715b007035ef18b5b2b" + integrity sha512-xPbdm2WKz1oH6pTkrJoUmr3OLuqvvcPYTQX0IIlc31tmDwDWPQjXGGFD/vwZGIZIkKaFpFxVMgAzfFScxox7dw== dependencies: - "@aws-sdk/types" "3.391.0" + "@aws-sdk/types" "3.418.0" "@smithy/property-provider" "^2.0.0" - "@smithy/shared-ini-file-loader" "^2.0.0" - "@smithy/types" "^2.2.0" + "@smithy/shared-ini-file-loader" "^2.0.6" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/credential-provider-sso@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.391.0.tgz#65dfe56596ce98eb7f4106b48e88fd0bd83d2290" - integrity sha512-FT/WoiRHiKys+FcRwvjui0yKuzNtJdn2uGuI1hYE0gpW1wVmW02ouufLckJTmcw09THUZ4w53OoCVU5OY00p8A== +"@aws-sdk/credential-provider-sso@3.421.0": + version "3.421.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.421.0.tgz#1863eabf232dd6add900e045e36a0e6c1213e31c" + integrity sha512-f8T3L5rhImL6T6RTSvbOxaWw9k2fDOT2DZbNjcPz9ITWmwXj2NNbdHGWuRi3dv2HoY/nW2IJdNxnhdhbn6Fc1A== dependencies: - "@aws-sdk/client-sso" "3.391.0" - "@aws-sdk/token-providers" "3.391.0" - "@aws-sdk/types" "3.391.0" + "@aws-sdk/client-sso" "3.421.0" + "@aws-sdk/token-providers" "3.418.0" + "@aws-sdk/types" "3.418.0" "@smithy/property-provider" "^2.0.0" - "@smithy/shared-ini-file-loader" "^2.0.0" - "@smithy/types" "^2.2.0" + "@smithy/shared-ini-file-loader" "^2.0.6" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/credential-provider-web-identity@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.391.0.tgz#c27aa6f2a215601a444ad7e3259f3ed55ccb39e7" - integrity sha512-n0vYg82B8bc4rxKltVbVqclev7hx+elyS9pEnZs3YbnbWJq0qqsznXmDfLqd1TcWpa09PGXcah0nsRDolVThsA== +"@aws-sdk/credential-provider-web-identity@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.418.0.tgz#c2aed2a79bf193c1fef2b98391aaa9de7336aaaf" + integrity sha512-do7ang565n9p3dS1JdsQY01rUfRx8vkxQqz5M8OlcEHBNiCdi2PvSjNwcBdrv/FKkyIxZb0TImOfBSt40hVdxQ== dependencies: - "@aws-sdk/types" "3.391.0" + "@aws-sdk/types" "3.418.0" "@smithy/property-provider" "^2.0.0" - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/middleware-bucket-endpoint@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.391.0.tgz#c9fb54062fc3b08c88721b0dc9427bd654d38b2d" - integrity sha512-R8poMkfi54kce6b0d9RQjNm2E+je/dpA1y/TTjCAoWfaBoq6X8UhX6ZD5wdlgg+38FK/2TPjrnXdsm4gtDJuUQ== +"@aws-sdk/middleware-bucket-endpoint@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.418.0.tgz#1c330fb4dd583454872db7eba3b6e06c0699d59d" + integrity sha512-gj/mj1UfbKkGbQ1N4YUvjTTp8BVs5fO1QAL2AjFJ+jfJOToLReX72aNEkm7sPGbHML0TqOY4cQbJuWYy+zdD5g== dependencies: - "@aws-sdk/types" "3.391.0" + "@aws-sdk/types" "3.418.0" "@aws-sdk/util-arn-parser" "3.310.0" - "@smithy/protocol-http" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/node-config-provider" "^2.0.12" + "@smithy/protocol-http" "^3.0.5" + "@smithy/types" "^2.3.3" "@smithy/util-config-provider" "^2.0.0" tslib "^2.5.0" -"@aws-sdk/middleware-expect-continue@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.391.0.tgz#b31f945f44d43aa1dbacbb04ecb0e2fb7e763739" - integrity sha512-BdZetUens7vx6PFcDehGTJGFYh/s2SyQk51r5u7OlzYTkdX6DhuBX2CzfzJbswFGKgSHXoiQY0WbSGmNOkRF3A== +"@aws-sdk/middleware-expect-continue@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.418.0.tgz#b621c6a8bc281f23bfd3791eaab25f687946d4a7" + integrity sha512-6x4rcIj685EmqDLQkbWoCur3Dg5DRClHMen6nHXmD3CR5Xyt3z1Gk/+jmZICxyJo9c6M4AeZht8o95BopkmYAQ== dependencies: - "@aws-sdk/types" "3.391.0" - "@smithy/protocol-http" "^2.0.3" - "@smithy/types" "^2.2.0" + "@aws-sdk/types" "3.418.0" + "@smithy/protocol-http" "^3.0.5" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/middleware-flexible-checksums@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.391.0.tgz#00dd581d05e4baabfeab18949927493eb5ff07b0" - integrity sha512-To9gjXzLvNQ6xbN2FtTFNjirvy1OmAuQR+mzZPgxFGgGKVPAKYz1+gFqHAEoFJVDyaxHMd8x4F7hEgDoPWQe7Q== +"@aws-sdk/middleware-flexible-checksums@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.418.0.tgz#a79f44739ec918d8947294d0acc52eb7eb358773" + integrity sha512-3O203dqS2JU5P1TAAbo7p1qplXQh59pevw9nqzPVb3EG8B+mSucVf2kKmF7kGHqKSk+nK/mB/4XGSsZBzGt6Wg== dependencies: "@aws-crypto/crc32" "3.0.0" "@aws-crypto/crc32c" "3.0.0" - "@aws-sdk/types" "3.391.0" + "@aws-sdk/types" "3.418.0" "@smithy/is-array-buffer" "^2.0.0" - "@smithy/protocol-http" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/protocol-http" "^3.0.5" + "@smithy/types" "^2.3.3" "@smithy/util-utf8" "^2.0.0" tslib "^2.5.0" -"@aws-sdk/middleware-host-header@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.391.0.tgz#80e9745880b671562ff115cd189ea929da51acc3" - integrity sha512-+nyNr0rb2ixY7mU48nibr7L7gsw37y4oELhqgnNKhcjZDJ34imBwKIMFa64n21FdftmhcjR8IdSpzXE9xrkJ8g== +"@aws-sdk/middleware-host-header@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.418.0.tgz#35d682e14f36c9d9d7464c7c1dd582bf6611436d" + integrity sha512-LrMTdzalkPw/1ujLCKPLwCGvPMCmT4P+vOZQRbSEVZPnlZk+Aj++aL/RaHou0jL4kJH3zl8iQepriBt4a7UvXQ== dependencies: - "@aws-sdk/types" "3.391.0" - "@smithy/protocol-http" "^2.0.3" - "@smithy/types" "^2.2.0" + "@aws-sdk/types" "3.418.0" + "@smithy/protocol-http" "^3.0.5" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/middleware-location-constraint@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.391.0.tgz#cddca8ed5d33b172fa237cde4572bbc3b4002b1b" - integrity sha512-2ff6/OU7XTMqIZHkyMu4V1xD1iAER/pyT0FNCX2fcc8b0wr0ltBmsJ5Zh+hfMs06/oPO36NDcvJMat/waghHgQ== +"@aws-sdk/middleware-location-constraint@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.418.0.tgz#e62e213a72ce583ba6135db51dcc60d07825b8ee" + integrity sha512-cc8M3VEaESHJhDsDV8tTpt2QYUprDWhvAVVSlcL43cTdZ54Quc0W+toDiaVOUlwrAZz2Y7g5NDj22ibJGFbOvw== dependencies: - "@aws-sdk/types" "3.391.0" - "@smithy/types" "^2.2.0" + "@aws-sdk/types" "3.418.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/middleware-logger@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.391.0.tgz#b0c61b3599dc9efddb6182337eb6362e3712dadc" - integrity sha512-KOwl5zo16b17JDhqILHBStccBQ2w35em7+/6vdkJdUII6OU8aVIFTlIQT9wOUvd4do6biIRBMZG3IK0Rg7mRDQ== +"@aws-sdk/middleware-logger@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.418.0.tgz#08d7419f4220c36032a070a7dbb8bbf7e744a9ce" + integrity sha512-StKGmyPVfoO/wdNTtKemYwoJsqIl4l7oqarQY7VSf2Mp3mqaa+njLViHsQbirYpyqpgUEusOnuTlH5utxJ1NsQ== dependencies: - "@aws-sdk/types" "3.391.0" - "@smithy/types" "^2.2.0" + "@aws-sdk/types" "3.418.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/middleware-recursion-detection@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.391.0.tgz#010334cd7945b4b6712f33e2bf0f54d69f214e7b" - integrity sha512-hVR3z59G7pX4pjDQs9Ag1tMgbLeGXOzeAAaNP9fEtHSd3KBMAGQgN3K3b9WPjzE2W0EoloHRJMK4qxZErdde2g== +"@aws-sdk/middleware-recursion-detection@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.418.0.tgz#2bb80d084f946846ad4907f3d6e0b451787d62b1" + integrity sha512-kKFrIQglBLUFPbHSDy1+bbe3Na2Kd70JSUC3QLMbUHmqipXN8KeXRfAj7vTv97zXl0WzG0buV++WcNwOm1rFjg== dependencies: - "@aws-sdk/types" "3.391.0" - "@smithy/protocol-http" "^2.0.3" - "@smithy/types" "^2.2.0" + "@aws-sdk/types" "3.418.0" + "@smithy/protocol-http" "^3.0.5" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/middleware-sdk-s3@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.391.0.tgz#4b377cd9ddd6be79e5a76e9f105d48d8a7daa41d" - integrity sha512-/G77j3IdZFtzI6CWns5f//xOOJ8DezDD9sEvAlfSiBgJLaL3SUFZLmG+lHqEPzCQyNpNSY5RvuojtjloaLDi5A== +"@aws-sdk/middleware-sdk-s3@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.418.0.tgz#b1de52d54e0cbc8d46ce0bc4c6c54b527f409aaf" + integrity sha512-rei32LF45SyqL3NlWDjEOfMwAca9A5F4QgUyXJqvASc43oWC1tJnLIhiCxNh8qkWAiRyRzFpcanTeqyaRSsZpA== dependencies: - "@aws-sdk/types" "3.391.0" + "@aws-sdk/types" "3.418.0" "@aws-sdk/util-arn-parser" "3.310.0" - "@smithy/protocol-http" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/protocol-http" "^3.0.5" + "@smithy/smithy-client" "^2.1.6" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/middleware-sdk-sts@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.391.0.tgz#0e0254ab4c59577c8646ab67939039d977ba93c0" - integrity sha512-6ZXI3Z4QU+TnT5PwKWloGmRHG81tWeI18/zxf9wWzrO2NhYFvITzEJH0vWLLiXdWtn/BYfLULXtDvkTaepbI5A== +"@aws-sdk/middleware-sdk-sts@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.418.0.tgz#f167f16050e055282ddd60226a2216c84873d464" + integrity sha512-cW8ijrCTP+mgihvcq4+TbhAcE/we5lFl4ydRqvTdtcSnYQAVQADg47rnTScQiFsPFEB3NKq7BGeyTJF9MKolPA== dependencies: - "@aws-sdk/middleware-signing" "3.391.0" - "@aws-sdk/types" "3.391.0" - "@smithy/types" "^2.2.0" + "@aws-sdk/middleware-signing" "3.418.0" + "@aws-sdk/types" "3.418.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/middleware-signing@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.391.0.tgz#f16ca8a9a3fa750f4f0f6a4b1baeb4899bf675f6" - integrity sha512-2pAJJlZqaHc0d+cz2FTVrQmWi8ygKfqfczHUo/loCtOaMNtWXBHb/JsLEecs6cXdizy6gi3YsLz6VZYwY4Ssxw== +"@aws-sdk/middleware-signing@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.418.0.tgz#c7242b84069067bb671cb4191d412b59713a375e" + integrity sha512-onvs5KoYQE8OlOE740RxWBGtsUyVIgAo0CzRKOQO63ZEYqpL1Os+MS1CGzdNhvQnJgJruE1WW+Ix8fjN30zKPA== dependencies: - "@aws-sdk/types" "3.391.0" + "@aws-sdk/types" "3.418.0" "@smithy/property-provider" "^2.0.0" - "@smithy/protocol-http" "^2.0.3" + "@smithy/protocol-http" "^3.0.5" "@smithy/signature-v4" "^2.0.0" - "@smithy/types" "^2.2.0" - "@smithy/util-middleware" "^2.0.0" + "@smithy/types" "^2.3.3" + "@smithy/util-middleware" "^2.0.2" tslib "^2.5.0" -"@aws-sdk/middleware-ssec@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.391.0.tgz#514754024232b1307463cd0b88751eaa27c92c7d" - integrity sha512-Mhz0wBWccjwmFNb9zNLQD9HpPfU/Ygv7HtaPAkcmnWOMuUNhAS6aXExZc3QGE2owzAaLS2g3m24JEE3LsIYZJQ== +"@aws-sdk/middleware-ssec@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.418.0.tgz#67b554c4acad81c7aa93421c8fcba8a18e138294" + integrity sha512-J7K+5h6aP7IYMlu/NwHEIjb0+WDu1eFvO8TCPo6j1H9xYRi8B/6h+6pa9Rk9IgRUzFnrdlDu9FazG8Tp0KKLyg== dependencies: - "@aws-sdk/types" "3.391.0" - "@smithy/types" "^2.2.0" + "@aws-sdk/types" "3.418.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/middleware-user-agent@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.391.0.tgz#bcbafbefc1e04966acab4f19662c8a4cea90e7a4" - integrity sha512-LdK9uMNA14zqRw3B79Mhy7GX36qld/GYo93xuu+lr+AQ98leZEdc6GUbrtNDI3fP1Z8TMQcyHUKBml4/B+wXpQ== +"@aws-sdk/middleware-user-agent@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.418.0.tgz#37426cf801332165fb170b1fd62dea8bb967a1ef" + integrity sha512-Jdcztg9Tal9SEAL0dKRrnpKrm6LFlWmAhvuwv0dQ7bNTJxIxyEFbpqdgy7mpQHsLVZgq1Aad/7gT/72c9igyZw== dependencies: - "@aws-sdk/types" "3.391.0" - "@aws-sdk/util-endpoints" "3.391.0" - "@smithy/protocol-http" "^2.0.3" - "@smithy/types" "^2.2.0" + "@aws-sdk/types" "3.418.0" + "@aws-sdk/util-endpoints" "3.418.0" + "@smithy/protocol-http" "^3.0.5" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/signature-v4-crt@^3.378.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-crt/-/signature-v4-crt-3.391.0.tgz#31d5f55fa1f0c0c890b5f3ad78ff35abd8025095" - integrity sha512-OVLCmbJcNA78ZPO7mGVH/ocXoW+oJvqVddVFNaoczdoFQxwAC/zLe20sMSiaSftmRSLZXac/ChJ06vwSaNFg5Q== +"@aws-sdk/region-config-resolver@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.418.0.tgz#53b99e4bd92f3369f51e9a76534b7d884db67526" + integrity sha512-lJRZ/9TjZU6yLz+mAwxJkcJZ6BmyYoIJVo1p5+BN//EFdEmC8/c0c9gXMRzfISV/mqWSttdtccpAyN4/goHTYA== + dependencies: + "@smithy/node-config-provider" "^2.0.12" + "@smithy/types" "^2.3.3" + "@smithy/util-config-provider" "^2.0.0" + "@smithy/util-middleware" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/signature-v4-crt@^3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-crt/-/signature-v4-crt-3.418.0.tgz#55bfd7a08f03efd831b3edaaa9b84342113afc85" + integrity sha512-4DNHPy8xxtKtyjAQdTwStiuEhe39GTte1KoZY+rRRsB5A6NPQB2N+Q5eEtoN6XGL9x4Ga5vQpseuHFMKB0Ll/A== dependencies: + "@aws-sdk/signature-v4-multi-region" "3.418.0" "@smithy/querystring-parser" "^2.0.0" "@smithy/signature-v4" "^2.0.0" - "@smithy/util-middleware" "^2.0.0" + "@smithy/types" "^2.3.3" + "@smithy/util-middleware" "^2.0.2" aws-crt "^1.15.9" tslib "^2.5.0" -"@aws-sdk/signature-v4-multi-region@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.391.0.tgz#fe76e27245a1973a4b75b6052bc2133ac56fad32" - integrity sha512-YMBWCkk8/Q85mqyf5eOn/XxAYflmxikYAU9ZL11fu9zPTUU2JsrsMJrsQmqia+Lp1jhQNQ9K3QFngG1hECflgQ== +"@aws-sdk/signature-v4-multi-region@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.418.0.tgz#984c8fc948c61a7ad02f1ccc6c2ddecf43a265b1" + integrity sha512-LeVYMZeUQUURFqDf4yZxTEv016g64hi0LqYBjU0mjwd8aPc0k6hckwvshezc80jCNbuLyjNfQclvlg3iFliItQ== dependencies: - "@aws-sdk/types" "3.391.0" - "@smithy/protocol-http" "^2.0.3" + "@aws-sdk/types" "3.418.0" + "@smithy/protocol-http" "^3.0.5" "@smithy/signature-v4" "^2.0.0" - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@aws-sdk/token-providers@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.391.0.tgz#a6706d88e3a5d603c263a4d505fd1186e9cee171" - integrity sha512-kgfArsKLDJE71qQjfXiHiM5cZqgDHlMsqEx35+A65GmTWJaS1PGDqu3ZvVVU8E5mxnCCLw7vho21fsjvH6TBpg== +"@aws-sdk/token-providers@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.418.0.tgz#cbfac922df397e72daf6dbdd8c1e9a140df0aa0e" + integrity sha512-9P7Q0VN0hEzTngy3Sz5eya2qEOEf0Q8qf1vB3um0gE6ID6EVAdz/nc/DztfN32MFxk8FeVBrCP5vWdoOzmd72g== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/middleware-host-header" "3.391.0" - "@aws-sdk/middleware-logger" "3.391.0" - "@aws-sdk/middleware-recursion-detection" "3.391.0" - "@aws-sdk/middleware-user-agent" "3.391.0" - "@aws-sdk/types" "3.391.0" - "@aws-sdk/util-endpoints" "3.391.0" - "@aws-sdk/util-user-agent-browser" "3.391.0" - "@aws-sdk/util-user-agent-node" "3.391.0" - "@smithy/config-resolver" "^2.0.3" - "@smithy/fetch-http-handler" "^2.0.3" - "@smithy/hash-node" "^2.0.3" - "@smithy/invalid-dependency" "^2.0.3" - "@smithy/middleware-content-length" "^2.0.3" - "@smithy/middleware-endpoint" "^2.0.3" - "@smithy/middleware-retry" "^2.0.3" - "@smithy/middleware-serde" "^2.0.3" - "@smithy/middleware-stack" "^2.0.0" - "@smithy/node-config-provider" "^2.0.3" - "@smithy/node-http-handler" "^2.0.3" + "@aws-sdk/middleware-host-header" "3.418.0" + "@aws-sdk/middleware-logger" "3.418.0" + "@aws-sdk/middleware-recursion-detection" "3.418.0" + "@aws-sdk/middleware-user-agent" "3.418.0" + "@aws-sdk/types" "3.418.0" + "@aws-sdk/util-endpoints" "3.418.0" + "@aws-sdk/util-user-agent-browser" "3.418.0" + "@aws-sdk/util-user-agent-node" "3.418.0" + "@smithy/config-resolver" "^2.0.10" + "@smithy/fetch-http-handler" "^2.1.5" + "@smithy/hash-node" "^2.0.9" + "@smithy/invalid-dependency" "^2.0.9" + "@smithy/middleware-content-length" "^2.0.11" + "@smithy/middleware-endpoint" "^2.0.9" + "@smithy/middleware-retry" "^2.0.12" + "@smithy/middleware-serde" "^2.0.9" + "@smithy/middleware-stack" "^2.0.2" + "@smithy/node-config-provider" "^2.0.12" + "@smithy/node-http-handler" "^2.1.5" "@smithy/property-provider" "^2.0.0" - "@smithy/protocol-http" "^2.0.3" - "@smithy/shared-ini-file-loader" "^2.0.0" - "@smithy/smithy-client" "^2.0.3" - "@smithy/types" "^2.2.0" - "@smithy/url-parser" "^2.0.3" + "@smithy/protocol-http" "^3.0.5" + "@smithy/shared-ini-file-loader" "^2.0.6" + "@smithy/smithy-client" "^2.1.6" + "@smithy/types" "^2.3.3" + "@smithy/url-parser" "^2.0.9" "@smithy/util-base64" "^2.0.0" "@smithy/util-body-length-browser" "^2.0.0" - "@smithy/util-body-length-node" "^2.0.0" - "@smithy/util-defaults-mode-browser" "^2.0.3" - "@smithy/util-defaults-mode-node" "^2.0.3" - "@smithy/util-retry" "^2.0.0" + "@smithy/util-body-length-node" "^2.1.0" + "@smithy/util-defaults-mode-browser" "^2.0.10" + "@smithy/util-defaults-mode-node" "^2.0.12" + "@smithy/util-retry" "^2.0.2" "@smithy/util-utf8" "^2.0.0" tslib "^2.5.0" -"@aws-sdk/types@3.391.0", "@aws-sdk/types@^3.222.0": +"@aws-sdk/types@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.418.0.tgz#c23213110b0c313d5546c810da032a441682f49a" + integrity sha512-y4PQSH+ulfFLY0+FYkaK4qbIaQI9IJNMO2xsxukW6/aNoApNymN1D2FSi2la8Qbp/iPjNDKsG8suNPm9NtsWXQ== + dependencies: + "@smithy/types" "^2.3.3" + tslib "^2.5.0" + +"@aws-sdk/types@^3.222.0": version "3.391.0" resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.391.0.tgz#d49b0130943f0c60fd9bc99b2a47ec9720e2dd07" integrity sha512-QpYVFKMOnzHz/JMj/b8wb18qxiT92U/5r5MmtRz2R3LOH6ooTO96k4ozXCrYr0qNed1PAnOj73rPrrH2wnCJKQ== @@ -591,12 +661,12 @@ dependencies: tslib "^2.5.0" -"@aws-sdk/util-endpoints@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.391.0.tgz#eb93e1331bd93773c05938001298a6c28e6db571" - integrity sha512-zv4sYDTQhNxyLoekcE02/nk3xvoo6yCHDy1kDJk0MFxOKaqUB+CvZdQBR4YBLSDlD4o4DUBmdYgKT58FfbM8sQ== +"@aws-sdk/util-endpoints@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.418.0.tgz#462c976f054fe260562d4d2844152a04dd883fd7" + integrity sha512-sYSDwRTl7yE7LhHkPzemGzmIXFVHSsi3AQ1KeNEk84eBqxMHHcCc2kqklaBk2roXWe50QDgRMy1ikZUxvtzNHQ== dependencies: - "@aws-sdk/types" "3.391.0" + "@aws-sdk/types" "3.418.0" tslib "^2.5.0" "@aws-sdk/util-locate-window@^3.0.0": @@ -606,7 +676,7 @@ dependencies: tslib "^2.5.0" -"@aws-sdk/util-stream-node@^3.360.0": +"@aws-sdk/util-stream-node@^3.370.0": version "3.374.0" resolved "https://registry.yarnpkg.com/@aws-sdk/util-stream-node/-/util-stream-node-3.374.0.tgz#249947b048bc17a3d4d3e4996b3950a5fa465aeb" integrity sha512-E9niTpJC9vYQAlManm8cpXGxMmSOBwGQj0TwLGECIaA51Bk+7RjlXAZkcu85PvIps90N3ollYtWWSsRBnH2SJw== @@ -614,24 +684,24 @@ "@smithy/util-stream-node" "^1.0.2" tslib "^2.5.0" -"@aws-sdk/util-user-agent-browser@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.391.0.tgz#8ae8f4c9133be90a1ad9efe06b3e1f1ecdad24a6" - integrity sha512-6ipHOB1WdCBNeAMJauN7l2qNE0WLVaTNhkD290/ElXm1FHGTL8yw6lIDIjhIFO1bmbZxDiKApwDiG7ROhaJoxQ== +"@aws-sdk/util-user-agent-browser@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.418.0.tgz#dc76b8e7e5cae3f827d68cd4a3ee30c0d475a39c" + integrity sha512-c4p4mc0VV/jIeNH0lsXzhJ1MpWRLuboGtNEpqE4s1Vl9ck2amv9VdUUZUmHbg+bVxlMgRQ4nmiovA4qIrqGuyg== dependencies: - "@aws-sdk/types" "3.391.0" - "@smithy/types" "^2.2.0" + "@aws-sdk/types" "3.418.0" + "@smithy/types" "^2.3.3" bowser "^2.11.0" tslib "^2.5.0" -"@aws-sdk/util-user-agent-node@3.391.0": - version "3.391.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.391.0.tgz#f15961e3ce64354912f16a644e1db27d2d431f42" - integrity sha512-PVvAK/Lf4BdB1eJIZtyFpGSslGQwKpYt9/hKs5NlR+qxBMXU9T0DnTqH4GiXZaazvXr7OUVWitIF2b7iKBMTow== +"@aws-sdk/util-user-agent-node@3.418.0": + version "3.418.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.418.0.tgz#7d5a1c82ce3265ff0f70b13d58d08593113ab99a" + integrity sha512-BXMskXFtg+dmzSCgmnWOffokxIbPr1lFqa1D9kvM3l3IFRiFGx2IyDg+8MAhq11aPDLvoa/BDuQ0Yqma5izOhg== dependencies: - "@aws-sdk/types" "3.391.0" - "@smithy/node-config-provider" "^2.0.3" - "@smithy/types" "^2.2.0" + "@aws-sdk/types" "3.418.0" + "@smithy/node-config-provider" "^2.0.12" + "@smithy/types" "^2.3.3" tslib "^2.5.0" "@aws-sdk/util-utf8-browser@^3.0.0", "@aws-sdk/util-utf8-browser@^3.109.0": @@ -903,6 +973,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.23.2": + version "7.23.4" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.4.tgz#36fa1d2b36db873d25ec631dcc4923fdc1cf2e2e" + integrity sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.22.5", "@babel/template@^7.3.3": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" @@ -1200,6 +1277,11 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": + version "1.6.0" + resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -1207,6 +1289,15 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + "@discoveryjs/json-ext@^0.5.0": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" @@ -1322,7 +1413,7 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.2.tgz#1205014625790c7ff0e471644a878a65d1e34ab0" integrity sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw== -"@eslint-community/eslint-utils@^4.2.0": +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== @@ -1334,6 +1425,11 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw== +"@eslint-community/regexpp@^4.5.1": + version "4.10.0" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + "@eslint/eslintrc@^2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" @@ -1349,10 +1445,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@^8.47.0": - version "8.47.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.47.0.tgz#5478fdf443ff8158f9de171c704ae45308696c7d" - integrity sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og== +"@eslint/js@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c" + integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA== "@ethereum-waffle/chai@4.0.10": version "4.0.10" @@ -1913,32 +2009,32 @@ read-pkg-up "^7.0.1" semver "^7.3.5" -"@google-cloud/paginator@^3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@google-cloud/paginator/-/paginator-3.0.7.tgz#fb6f8e24ec841f99defaebf62c75c2e744dd419b" - integrity sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ== +"@google-cloud/paginator@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@google-cloud/paginator/-/paginator-5.0.0.tgz#b8cc62f151685095d11467402cbf417c41bf14e6" + integrity sha512-87aeg6QQcEPxGCOthnpUjvw4xAZ57G7pL8FS0C4e/81fr3FjkpUpibf1s2v5XGyGhUVGF4Jfg7yEcxqn2iUw1w== dependencies: arrify "^2.0.0" extend "^3.0.2" -"@google-cloud/projectify@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@google-cloud/projectify/-/projectify-3.0.0.tgz#302b25f55f674854dce65c2532d98919b118a408" - integrity sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA== +"@google-cloud/projectify@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@google-cloud/projectify/-/projectify-4.0.0.tgz#d600e0433daf51b88c1fa95ac7f02e38e80a07be" + integrity sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA== -"@google-cloud/promisify@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@google-cloud/promisify/-/promisify-3.0.1.tgz#8d724fb280f47d1ff99953aee0c1669b25238c2e" - integrity sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA== +"@google-cloud/promisify@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@google-cloud/promisify/-/promisify-4.0.0.tgz#a906e533ebdd0f754dca2509933334ce58b8c8b1" + integrity sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g== -"@google-cloud/storage@^7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@google-cloud/storage/-/storage-7.0.1.tgz#38c267bb8377d442066d4eccb4f942f58d119476" - integrity sha512-YBJ8HaDZvbeVDgEGWuC6sCsfZNCooVfKg1J+CJ4iXwRejIWbKFjl8laWz8w+/+ucJHM9qOdGkB95Q/mhh2CX/A== +"@google-cloud/storage@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@google-cloud/storage/-/storage-7.1.0.tgz#c76ff48350d2e83989cc1050c29549ace55787a1" + integrity sha512-kAtniePZT5Ms9wayYcbT44H+1jwkYvRaA+E3IGnmBLG+aGwMTM0q9Xn0CCIez4D8toeBYczNkhQsQfRT1TDy7A== dependencies: - "@google-cloud/paginator" "^3.0.7" - "@google-cloud/projectify" "^3.0.0" - "@google-cloud/promisify" "^3.0.0" + "@google-cloud/paginator" "^5.0.0" + "@google-cloud/projectify" "^4.0.0" + "@google-cloud/promisify" "^4.0.0" abort-controller "^3.0.0" async-retry "^1.3.3" compressible "^2.0.12" @@ -1968,12 +2064,12 @@ ws "*" xtend "^4.0.0" -"@humanwhocodes/config-array@^0.11.10": - version "0.11.10" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" - integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" + "@humanwhocodes/object-schema" "^2.0.1" debug "^4.1.1" minimatch "^3.0.5" @@ -1982,10 +2078,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== "@hutson/parse-repository-url@^3.0.0": version "3.0.2" @@ -2020,61 +2116,61 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.6.2.tgz#bf1d4101347c23e07c029a1b1ae07d550f5cc541" - integrity sha512-0N0yZof5hi44HAR2pPS+ikJ3nzKNoZdVu8FffRf3wy47I7Dm7etk/3KetMdRUqzVd16V4O2m2ISpNTbnIuqy1w== +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^29.6.2" - jest-util "^29.6.2" + jest-message-util "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" -"@jest/core@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.6.2.tgz#6f2d1dbe8aa0265fcd4fb8082ae1952f148209c8" - integrity sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg== +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== dependencies: - "@jest/console" "^29.6.2" - "@jest/reporters" "^29.6.2" - "@jest/test-result" "^29.6.2" - "@jest/transform" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" ci-info "^3.2.0" exit "^0.1.2" graceful-fs "^4.2.9" - jest-changed-files "^29.5.0" - jest-config "^29.6.2" - jest-haste-map "^29.6.2" - jest-message-util "^29.6.2" - jest-regex-util "^29.4.3" - jest-resolve "^29.6.2" - jest-resolve-dependencies "^29.6.2" - jest-runner "^29.6.2" - jest-runtime "^29.6.2" - jest-snapshot "^29.6.2" - jest-util "^29.6.2" - jest-validate "^29.6.2" - jest-watcher "^29.6.2" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" micromatch "^4.0.4" - pretty-format "^29.6.2" + pretty-format "^29.7.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.6.2.tgz#794c0f769d85e7553439d107d3f43186dc6874a9" - integrity sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q== +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== dependencies: - "@jest/fake-timers" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.6.2" + jest-mock "^29.7.0" "@jest/expect-utils@^28.1.3": version "28.1.3" @@ -2090,46 +2186,53 @@ dependencies: jest-get-type "^29.4.3" -"@jest/expect@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.6.2.tgz#5a2ad58bb345165d9ce0a1845bbf873c480a4b28" - integrity sha512-m6DrEJxVKjkELTVAztTLyS/7C92Y2b0VYqmDROYKLLALHn8T/04yPs70NADUYPrV3ruI+H3J0iUIuhkjp7vkfg== +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== dependencies: - expect "^29.6.2" - jest-snapshot "^29.6.2" + jest-get-type "^29.6.3" -"@jest/fake-timers@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.6.2.tgz#fe9d43c5e4b1b901168fe6f46f861b3e652a2df4" - integrity sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA== +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== dependencies: - "@jest/types" "^29.6.1" + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" "@sinonjs/fake-timers" "^10.0.2" "@types/node" "*" - jest-message-util "^29.6.2" - jest-mock "^29.6.2" - jest-util "^29.6.2" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" -"@jest/globals@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.2.tgz#74af81b9249122cc46f1eb25793617eec69bf21a" - integrity sha512-cjuJmNDjs6aMijCmSa1g2TNG4Lby/AeU7/02VtpW+SLcZXzOLK2GpN2nLqcFjmhy3B3AoPeQVx7BnyOf681bAw== +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: - "@jest/environment" "^29.6.2" - "@jest/expect" "^29.6.2" - "@jest/types" "^29.6.1" - jest-mock "^29.6.2" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" -"@jest/reporters@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.6.2.tgz#524afe1d76da33d31309c2c4a2c8062d0c48780a" - integrity sha512-sWtijrvIav8LgfJZlrGCdN0nP2EWbakglJY49J1Y5QihcQLfy7ovyxxjJBRXMNltgt4uPtEcFmIMbVshEDfFWw== +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.6.2" - "@jest/test-result" "^29.6.2" - "@jest/transform" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@jridgewell/trace-mapping" "^0.3.18" "@types/node" "*" chalk "^4.0.0" @@ -2138,13 +2241,13 @@ glob "^7.1.3" graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" + istanbul-lib-instrument "^6.0.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-message-util "^29.6.2" - jest-util "^29.6.2" - jest-worker "^29.6.2" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" slash "^3.0.0" string-length "^4.0.1" strip-ansi "^6.0.0" @@ -2164,51 +2267,58 @@ dependencies: "@sinclair/typebox" "^0.27.8" -"@jest/source-map@^29.6.0": - version "29.6.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.0.tgz#bd34a05b5737cb1a99d43e1957020ac8e5b9ddb1" - integrity sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA== +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: "@jridgewell/trace-mapping" "^0.3.18" callsites "^3.0.0" graceful-fs "^4.2.9" -"@jest/test-result@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.6.2.tgz#fdd11583cd1608e4db3114e8f0cce277bf7a32ed" - integrity sha512-3VKFXzcV42EYhMCsJQURptSqnyjqCGbtLuX5Xxb6Pm6gUf1wIRIl+mandIRGJyWKgNKYF9cnstti6Ls5ekduqw== +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: - "@jest/console" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.6.2.tgz#585eff07a68dd75225a7eacf319780cb9f6b9bf4" - integrity sha512-GVYi6PfPwVejO7slw6IDO0qKVum5jtrJ3KoLGbgBWyr2qr4GaxFV6su+ZAjdTX75Sr1DkMFRk09r2ZVa+wtCGw== +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== dependencies: - "@jest/test-result" "^29.6.2" + "@jest/test-result" "^29.7.0" graceful-fs "^4.2.9" - jest-haste-map "^29.6.2" + jest-haste-map "^29.7.0" slash "^3.0.0" -"@jest/transform@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.2.tgz#522901ebbb211af08835bc3bcdf765ab778094e3" - integrity sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg== +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: "@babel/core" "^7.11.6" - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@jridgewell/trace-mapping" "^0.3.18" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" convert-source-map "^2.0.0" fast-json-stable-stringify "^2.1.0" graceful-fs "^4.2.9" - jest-haste-map "^29.6.2" - jest-regex-util "^29.4.3" - jest-util "^29.6.2" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" micromatch "^4.0.4" pirates "^4.0.4" slash "^3.0.0" @@ -2238,6 +2348,18 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" @@ -2286,21 +2408,21 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@lerna/child-process@7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-7.1.5.tgz#a01e8821fb7b17a68d1c1527127543af6cf27f1b" - integrity sha512-YXmxzxXTP3u9HQpSXvK8qqoAm7VWQIFria3FVMQKkOSkWkph1TNnvt3Q1JvKT7/Jgd1HfTc3QrK09a2FND9+8A== +"@lerna/child-process@7.4.2": + version "7.4.2" + resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-7.4.2.tgz#a2fd013ac2150dc288270d3e0d0b850c06bec511" + integrity sha512-je+kkrfcvPcwL5Tg8JRENRqlbzjdlZXyaR88UcnCdNW0AJ1jX9IfHRys1X7AwSroU2ug8ESNC+suoBw1vX833Q== dependencies: chalk "^4.1.0" execa "^5.0.0" strong-log-transformer "^2.1.0" -"@lerna/create@7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-7.1.5.tgz#180b26f028be25b541a327429168da6c10bdb265" - integrity sha512-/CDI/cvXJbycgSDzWXzP7DBuJ10qL/uYEouFt3/mxi9+hSfM885fu6lbVPV7QOf8A0otXcTs7PN2dVyMrnWQeg== +"@lerna/create@7.4.2": + version "7.4.2" + resolved "https://registry.yarnpkg.com/@lerna/create/-/create-7.4.2.tgz#f845fad1480e46555af98bd39af29571605dddc9" + integrity sha512-1wplFbQ52K8E/unnqB0Tq39Z4e+NEoNrpovEnl6GpsTUrC6WDp8+w0Le2uCBV0hXyemxChduCkLz4/y1H1wTeg== dependencies: - "@lerna/child-process" "7.1.5" + "@lerna/child-process" "7.4.2" "@npmcli/run-script" "6.0.2" "@nx/devkit" ">=16.5.1 < 17" "@octokit/plugin-enterprise-rest" "6.0.1" @@ -2325,12 +2447,13 @@ ini "^1.3.8" init-package-json "5.0.0" inquirer "^8.2.4" + is-ci "3.0.1" is-stream "2.0.0" js-yaml "4.1.0" libnpmpublish "7.3.0" load-json-file "6.2.0" lodash "^4.17.21" - make-dir "3.1.0" + make-dir "4.0.0" minimatch "3.0.5" multimatch "5.0.0" node-fetch "2.6.7" @@ -2398,6 +2521,13 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" +"@next/eslint-plugin-next@13.5.6": + version "13.5.6" + resolved "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.6.tgz#cf279b94ddc7de49af8e8957f0c3b7349bc489bf" + integrity sha512-ng7pU/DDsxPgT6ZPvuprxrkeew3XaRf4LAT4FabaEO/hAbvVx4P7wqnqdbTdDn1kgTvsI4tpIgT4Awn/m0bGbg== + dependencies: + glob "7.1.7" + "@noble/curves@1.1.0", "@noble/curves@~1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" @@ -2405,6 +2535,13 @@ dependencies: "@noble/hashes" "1.3.1" +"@noble/curves@1.2.0", "@noble/curves@~1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" @@ -2415,6 +2552,11 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== +"@noble/hashes@1.3.2", "@noble/hashes@~1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + "@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" @@ -2819,16 +2961,16 @@ before-after-hook "^2.2.0" universal-user-agent "^6.0.0" -"@octokit/core@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-5.0.0.tgz#0fc2b6eb88437e5c1d69f756a5dcee7472d2b2dd" - integrity sha512-YbAtMWIrbZ9FCXbLwT9wWB8TyLjq9mxpKdgB3dUNxQcIVTf9hJ70gRPwAcqGZdY6WdJPZ0I7jLaaNDCiloGN2A== +"@octokit/core@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-5.0.1.tgz#865da2b30d54354cccb6e30861ddfa0e24494780" + integrity sha512-lyeeeZyESFo+ffI801SaBKmCfsvarO+dgV8/0gD8u1d87clbEdWsP5yC+dSj3zLhb2eIf5SJrn6vDz9AheETHw== dependencies: "@octokit/auth-token" "^4.0.0" "@octokit/graphql" "^7.0.0" "@octokit/request" "^8.0.2" "@octokit/request-error" "^5.0.0" - "@octokit/types" "^11.0.0" + "@octokit/types" "^12.0.0" before-after-hook "^2.2.0" universal-user-agent "^6.0.0" @@ -2873,6 +3015,11 @@ resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-18.0.0.tgz#f43d765b3c7533fd6fb88f3f25df079c24fccf69" integrity sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw== +"@octokit/openapi-types@^19.0.0": + version "19.0.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-19.0.0.tgz#0101bf62ab14c1946149a0f8385440963e1253c4" + integrity sha512-PclQ6JGMTE9iUStpzMkwLCISFn/wDeRjkZFIKALpvJQNBGwDoYYi2fFvuHwssoQ1rXI5mfh6jgTgWuddeUzfWw== + "@octokit/plugin-enterprise-rest@6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" @@ -2968,6 +3115,13 @@ dependencies: "@octokit/openapi-types" "^18.0.0" +"@octokit/types@^12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-12.0.0.tgz#6b34309288b6f5ac9761d2589e3165cde1b95fee" + integrity sha512-EzD434aHTFifGudYAygnFlS1Tl6KhbTynEWELQXIbTY8Msvb5nEqTZIm7sbPEt4mQYLZwu3zPKVdeIrw0g7ovg== + dependencies: + "@octokit/openapi-types" "^19.0.0" + "@octokit/types@^9.0.0", "@octokit/types@^9.2.3": version "9.3.2" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.3.2.tgz#3f5f89903b69f6a2d196d78ec35f888c0013cac5" @@ -3118,11 +3272,21 @@ path-browserify "^1.0.0" url "^0.11.0" +"@rushstack/eslint-patch@^1.3.3": + version "1.6.0" + resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.6.0.tgz#1898e7a7b943680d757417a47fb10f5fcc230b39" + integrity sha512-2/U3GXA6YiPYQDLGwtGlnNgKYBSwCFIHf8Y9LUY5VATHdtbLlU0Y1R3QoBnT0aB4qv/BEiVVsj7LJXoQCgJ2vA== + "@scure/base@~1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== +"@scure/base@~1.1.2": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.3.tgz#8584115565228290a6c6c4961973e0903bb3df2f" + integrity sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q== + "@scure/bip32@1.1.5": version "1.1.5" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" @@ -3141,6 +3305,15 @@ "@noble/hashes" "~1.3.1" "@scure/base" "~1.1.0" +"@scure/bip32@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.2.tgz#90e78c027d5e30f0b22c1f8d50ff12f3fb7559f8" + integrity sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA== + dependencies: + "@noble/curves" "~1.2.0" + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.2" + "@scure/bip39@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" @@ -3321,12 +3494,12 @@ "@smithy/types" "^1.2.0" tslib "^2.5.0" -"@smithy/abort-controller@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-2.0.3.tgz#7e7141b6c2fa90f21f4df38d3ef792f5308f94ce" - integrity sha512-LbQ4fdsVuQC3/18Z/uia5wnk9fk8ikfHl3laYCEGhboEMJ/6oVk3zhydqljMxBCftHGUv7yUrTnZ6EAQhOf+PA== +"@smithy/abort-controller@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-2.0.9.tgz#f4b9ce1a9a09d446cf24d8bc1abc2b3b524cd7cd" + integrity sha512-8liHOEbx99xcy4VndeQNQhyA0LS+e7UqsuRnDTSIA26IKBv/7vA9w09KOd4fgNULrvX0r3WpA6cwsQTRJpSWkg== dependencies: - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" "@smithy/chunked-blob-reader-native@^2.0.0": @@ -3344,17 +3517,18 @@ dependencies: tslib "^2.5.0" -"@smithy/config-resolver@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-2.0.3.tgz#e81fb1ad688ab28d06203bbaf96098d8c391c629" - integrity sha512-E+fsc6BOzFOc6U6y9ogRH8Pw2HF1NVW14AAYy7l3OTXYWuYxHb/fzDZaA0FvD/dXyFoMy7AV1rYZsGzD4bMKzw== +"@smithy/config-resolver@^2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-2.0.10.tgz#974de532e6048d86b8b7aa1fed17a75c558c41c8" + integrity sha512-MwToDsCltHjumkCuRn883qoNeJUawc2b8sX9caSn5vLz6J5crU1IklklNxWCaMO2z2nDL91Po4b/aI1eHv5PfA== dependencies: - "@smithy/types" "^2.2.0" + "@smithy/node-config-provider" "^2.0.12" + "@smithy/types" "^2.3.3" "@smithy/util-config-provider" "^2.0.0" - "@smithy/util-middleware" "^2.0.0" + "@smithy/util-middleware" "^2.0.2" tslib "^2.5.0" -"@smithy/credential-provider-imds@^2.0.0", "@smithy/credential-provider-imds@^2.0.3": +"@smithy/credential-provider-imds@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.3.tgz#93cc61deb3b363da1dc8359c254ad4bf8e1c8624" integrity sha512-2e85iLgSuiGQ8BBFkot88kuv6sT5DHvkDO8FDvGwNunn2ybf24HhEkaWCMxK4pUeHtnA2dMa3hZbtfmJ7KJQig== @@ -3365,6 +3539,17 @@ "@smithy/url-parser" "^2.0.3" tslib "^2.5.0" +"@smithy/credential-provider-imds@^2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.12.tgz#787dc731903dd1b07f5e35e6c1d63ca74d1d3356" + integrity sha512-S3lUNe+2fEFwKcmiQniXGPXt69vaHvQCw8kYQOBL4OvJsgwfpkIYDZdroHbTshYi0M6WaKL26Mw+hvgma6dZqA== + dependencies: + "@smithy/node-config-provider" "^2.0.12" + "@smithy/property-provider" "^2.0.10" + "@smithy/types" "^2.3.3" + "@smithy/url-parser" "^2.0.9" + tslib "^2.5.0" + "@smithy/eventstream-codec@^2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-2.0.3.tgz#cb4403497feadf99213762940ac1e825c1f78372" @@ -3375,87 +3560,97 @@ "@smithy/util-hex-encoding" "^2.0.0" tslib "^2.5.0" -"@smithy/eventstream-serde-browser@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.0.3.tgz#36f0386a9d0c6b8789b4db6bf31c4c9a24b48903" - integrity sha512-RwQeTFnc6nOP6iGjdnMFgDG8QtneHKptrVZxjc+be4KIoXGPyF3QAourxnrClxTl+MACXYUaCg6bWCozqfHMOw== +"@smithy/eventstream-codec@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-2.0.9.tgz#aa588d4083c9a16f14896d780e2fff0b34ef2c35" + integrity sha512-sy0pcbKnawt1iu+qCoSFbs/h9PAaUgvlJEO3lqkE1HFFj4p5RgL98vH+9CyDoj6YY82cG5XsorFmcLqQJHTOYw== dependencies: - "@smithy/eventstream-serde-universal" "^2.0.3" - "@smithy/types" "^2.2.0" + "@aws-crypto/crc32" "3.0.0" + "@smithy/types" "^2.3.3" + "@smithy/util-hex-encoding" "^2.0.0" tslib "^2.5.0" -"@smithy/eventstream-serde-config-resolver@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.0.3.tgz#e07c15908bcefa6873c4f9107406c853d3fe7900" - integrity sha512-J8QzPnarBiJaPw5DBsZ5O2GHjfPHhCmKV5iVzdcAFt0PD81UWNL9HMwAKx99mY5WWPCaFKvb1yBeN2g/v4uA2w== +"@smithy/eventstream-serde-browser@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.0.9.tgz#9c595348d5e1a9c140a92bfe0235e9a282ef9c88" + integrity sha512-g70enHZau2hGj1Uxedrn8AAjH9E7RnpHdwkuPKapagah53ztbwI7xaNeA5SLD4MjSjdrjathyQBCQKIzwXrR1g== dependencies: - "@smithy/types" "^2.2.0" + "@smithy/eventstream-serde-universal" "^2.0.9" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@smithy/eventstream-serde-node@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.0.3.tgz#f595fb8322fc25289213e314a28f2f795f100873" - integrity sha512-085r0AHMhwVF99rlAy8RVMhXMkxay4SdSwRdDUIe4MXQ6r2957BVpm3BcoxRpjcGgnoCldRc9tCRa0TclvUS5w== +"@smithy/eventstream-serde-config-resolver@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.0.9.tgz#580a0f54182f90a61f50b84a675aed728d08f8af" + integrity sha512-+15GzIMtdSuRPyuCeGZ7gzgD94Ejv6eM1vKcqvipdzS+i36KTZ2A9aZsJk+gDw//OCD1EMx9SqpV6bUvMS4PWg== dependencies: - "@smithy/eventstream-serde-universal" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@smithy/eventstream-serde-universal@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.0.3.tgz#a360c45c91cd64b03f1ba60bb5e738e99bcb44ff" - integrity sha512-51nLy47MmU9Nb4dwlwsmP1XJViP72kuLtIqTeDeRSe5Ah4xfSP/df11roEhzUmE/rUYEkErj64RHkseeuFkCgg== +"@smithy/eventstream-serde-node@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.0.9.tgz#07109906bcbabe5c2f2c5f2cf3cd75f352f3ab75" + integrity sha512-UEJcvN2WXXEjkewtFkj1S2HSZLbyCgzUnfoFPrTuKy4+xRfakO5dNx6ws2h1pvb8Vc7mTuBL+Webl1R5mnVsXA== dependencies: - "@smithy/eventstream-codec" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/eventstream-serde-universal" "^2.0.9" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@smithy/fetch-http-handler@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-2.0.3.tgz#e53b6a65f25c9c3b20ec06fbc4795409381d82d6" - integrity sha512-0if2hyn+tDkyK9Tg1bXpo3IMUaezz/FKlaUTwTey3m87hF8gb7a0nKaST4NURE2eUVimViGCB7SH3/i4wFXALg== +"@smithy/eventstream-serde-universal@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.0.9.tgz#c8613768f14664c6b5fab299b24bb9141bbdecc3" + integrity sha512-dAHQEYlK/1tjjieBE7jjXwpLQFgKdkvC4HSQf+/Jj4t34XbUmXWHbw92/EuLp9+vjNB/JQPvkwpMtN31jxIDeg== dependencies: - "@smithy/protocol-http" "^2.0.3" - "@smithy/querystring-builder" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/eventstream-codec" "^2.0.9" + "@smithy/types" "^2.3.3" + tslib "^2.5.0" + +"@smithy/fetch-http-handler@^2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-2.1.5.tgz#0764e232482320b9f2f8ec9c79ebdfa214a761fb" + integrity sha512-BIeCHGfr5JCGN+EMTwZK74ELvjPXOIrI7OLM5OhZJJ6AmZyRv2S9ANJk18AtLwht0TsSm+8WoXIEp8LuxNgUyA== + dependencies: + "@smithy/protocol-http" "^3.0.5" + "@smithy/querystring-builder" "^2.0.9" + "@smithy/types" "^2.3.3" "@smithy/util-base64" "^2.0.0" tslib "^2.5.0" -"@smithy/hash-blob-browser@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-2.0.3.tgz#6198dd0382e6ddc9d3f27f7b4f85252c12af054d" - integrity sha512-YQywO2eGG4x3klQZ+R7G8X3oCgrzQaCNC3zYq7kcGibE2Z+q9Lzt3prYiODUwAihDJTCG09xHq1p9IW+z/fp+Q== +"@smithy/hash-blob-browser@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-2.0.9.tgz#e02caf03bdd036343bc53883330a1b03fc26a34e" + integrity sha512-JNWOV1ci9vIg4U82klNr07bZXsA6OCumqHugpvZdvvn6cNGwTa4rvpS5FpPcqKeh3Rdg1rr4h8g+X6zyOamnZw== dependencies: "@smithy/chunked-blob-reader" "^2.0.0" "@smithy/chunked-blob-reader-native" "^2.0.0" - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@smithy/hash-node@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-2.0.3.tgz#7ff71a884c00e7d0b4993f2a80a99f8d2cff86c4" - integrity sha512-wtN9eiRKEiryXrPbWQ7Acu0D3Uk65+PowtTqOslViMZNcKNlYHsxOP1S9rb2klnzA3yY1WSPO1tG78pjhRlvrQ== +"@smithy/hash-node@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-2.0.9.tgz#51811dabd2990eec1fc003dd6aaa8b8db95cc1eb" + integrity sha512-XP3yWd5wyCtiVmsY5Nuq/FUwyCEQ6YG7DsvRh7ThldNukGpCzyFdP8eivZJVjn4Fx7oYrrOnVoYZ0WEgpW1AvQ== dependencies: - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" "@smithy/util-buffer-from" "^2.0.0" "@smithy/util-utf8" "^2.0.0" tslib "^2.5.0" -"@smithy/hash-stream-node@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-2.0.3.tgz#3b3a6756792f3e27e617fa372766ba2aa8ca49bf" - integrity sha512-rFUhbuynRMd1DlYewqXRog2bZIMaDL3sNTAK7fg+7DngPpus7hiIGuXn3tJNnCiqiNuxVrhi/ffWpwt21+8DtA== +"@smithy/hash-stream-node@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-2.0.9.tgz#ecdfef5980702fd8449bdf0f9077b9fabbdfd5a9" + integrity sha512-3nrkMpiOrhsJvJS6K4OkP0qvA3U5r8PpseXULeGd1ZD1EbfcZ30Lvl72FGaaHskwWZyTPR4czr1d/RwLRCVHNA== dependencies: - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" "@smithy/util-utf8" "^2.0.0" tslib "^2.5.0" -"@smithy/invalid-dependency@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-2.0.3.tgz#d9471b1ee5904ee6ec49a61d5ffbc65412f1feb9" - integrity sha512-GtmVXD/s+OZlFG1o3HfUI55aBJZXX5/iznAQkgjRGf8prYoO8GvSZLDWHXJp91arybaJxYd133oJORGf4YxGAg== +"@smithy/invalid-dependency@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-2.0.9.tgz#9c8ebb70f0d1670490ae51c078d7240ac7cb9ddb" + integrity sha512-RuJqhYf8nViK96IIO9JbTtjDUuFItVfuuJhWw2yk7fv67yltQ7fZD6IQ2OsHHluoVmstnQJuCg5raXJR696Ubw== dependencies: - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" "@smithy/is-array-buffer@^1.1.0": @@ -3472,61 +3667,73 @@ dependencies: tslib "^2.5.0" -"@smithy/md5-js@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-2.0.3.tgz#fb9e7ace2ddbc385986e6b75352f1a68f4d9046b" - integrity sha512-pYnD2US3SioMynHytq4n2BsB5L6uJ7pWKxl9sQqvWwYJXcT3VSnJ0/9adbVcWE+GrMRlGO4CpRg9SIKpdQYR+Q== +"@smithy/md5-js@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-2.0.9.tgz#37eb5b6a4d8a978429623a91d3aa389c904ac1f5" + integrity sha512-ALHGoTZDgBXBbjCpQzVy6hpa6Rdr6e2jyEw51d6CQOUpHkUnFH7G96UWhVwUnkP0xozPCvmWy+3+j2QUX+oK9w== dependencies: - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" "@smithy/util-utf8" "^2.0.0" tslib "^2.5.0" -"@smithy/middleware-content-length@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-2.0.3.tgz#6481be833b9daecea710c09d67f89f67de09ba30" - integrity sha512-2FiZ5vu2+iMRL8XWNaREUqqNHjtBubaY9Jb2b3huZ9EbgrXsJfCszK6PPidHTLe+B4T7AISqdF4ZSp9VPXuelg== +"@smithy/middleware-content-length@^2.0.11": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-2.0.11.tgz#3d046f917cb0975caf6af2de96c9622cfa3c33ca" + integrity sha512-Malj4voNTL4+a5ZL3a6+Ij7JTUMTa2R7c3ZIBzMxN5OUUgAspU7uFi1Q97f4B0afVh2joQBAWH5IQJUG25nl8g== dependencies: - "@smithy/protocol-http" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/protocol-http" "^3.0.5" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@smithy/middleware-endpoint@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.3.tgz#47416bbe4237c5d7204f31aef02ce294c34667af" - integrity sha512-gNleUHhu5OKk/nrA6WbpLUk/Wk2hcyCvaw7sZiKMazs+zdzWb0kYzynRf675uCWolbvlw9BvkrVaSJo5TRz+Mg== +"@smithy/middleware-endpoint@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.9.tgz#2a8b5098cc124923a7104db7578314b4193a62f6" + integrity sha512-72/o8R6AAO4+nyTI6h4z6PYGTSA4dr1M7tZz29U8DEUHuh1YkhC77js0P6RyF9G0wDLuYqxb+Yh0crI5WG2pJg== dependencies: - "@smithy/middleware-serde" "^2.0.3" - "@smithy/types" "^2.2.0" - "@smithy/url-parser" "^2.0.3" - "@smithy/util-middleware" "^2.0.0" + "@smithy/middleware-serde" "^2.0.9" + "@smithy/types" "^2.3.3" + "@smithy/url-parser" "^2.0.9" + "@smithy/util-middleware" "^2.0.2" tslib "^2.5.0" -"@smithy/middleware-retry@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-2.0.3.tgz#419a1136a117da6abecd5aa6d0535a24152d530e" - integrity sha512-BpfaUwgOh8LpWP/x6KBb5IdBmd5+tEpTKIjDt7LWi3IVOYmRX5DjQo1eCEUqlKS1nxws/T7+/IyzvgBq8gF9rw== - dependencies: - "@smithy/protocol-http" "^2.0.3" - "@smithy/service-error-classification" "^2.0.0" - "@smithy/types" "^2.2.0" - "@smithy/util-middleware" "^2.0.0" - "@smithy/util-retry" "^2.0.0" +"@smithy/middleware-retry@^2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-2.0.12.tgz#d297d7cc5f40e8908aa1495060155b40e24f1ce7" + integrity sha512-YQ/ufXX4/d9/+Jf1QQ4J+CVeupC7BW52qldBTvRV33PDX9vxndlAwkFwzBcmnUFC3Hjf1//HW6I77EItcjNSCA== + dependencies: + "@smithy/node-config-provider" "^2.0.12" + "@smithy/protocol-http" "^3.0.5" + "@smithy/service-error-classification" "^2.0.2" + "@smithy/types" "^2.3.3" + "@smithy/util-middleware" "^2.0.2" + "@smithy/util-retry" "^2.0.2" tslib "^2.5.0" uuid "^8.3.2" -"@smithy/middleware-serde@^2.0.3": +"@smithy/middleware-serde@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-2.0.9.tgz#cf0028f18dc96648de212870c9726844084dd89a" + integrity sha512-GVbauxrr6WmtCaesakktg3t5LR/yDbajpC7KkWc8rtCpddMI4ShAVO5Q6DqwX8MDFi4CLaY8H7eTGcxhl3jbLg== + dependencies: + "@smithy/types" "^2.3.3" + tslib "^2.5.0" + +"@smithy/middleware-stack@^2.0.2", "@smithy/middleware-stack@^2.0.3": version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-2.0.3.tgz#637fb9abac625c232fa62aa9e10a5ae3146a84ba" - integrity sha512-5BxuOKL7pXqesvtunniDlvYQXVr7UJEF5nFVoK6+5chf5wplLA8IZWAn3NUcGq/f1u01w2m2q7atCoA6ftRLKA== + resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-2.0.3.tgz#86b9d13d7b01208b59f9510eb6b08f8556ef6915" + integrity sha512-AlhPmbwpkC4lQBVaVHXczmjFvsAhDHhrakqLt038qFLotnJcvDLhmMzAtu23alBeOSkKxkTQq0LsAt2N0WpAbw== dependencies: - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" -"@smithy/middleware-stack@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-2.0.0.tgz#cd9f442c2788b1ef0ea6b32236d80c76b3c342e9" - integrity sha512-31XC1xNF65nlbc16yuh3wwTudmqs6qy4EseQUGF8A/p2m/5wdd/cnXJqpniy/XvXVwkHPz/GwV36HqzHtIKATQ== +"@smithy/node-config-provider@^2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-2.0.12.tgz#59ef195dab5f00ea15abeb356e1fc2f41e4d54f2" + integrity sha512-df9y9ywv+JmS40Y60ZqJ4jfZiTCmyHQffwzIqjBjLJLJl0imf9F6DWBd+jiEWHvlohR+sFhyY+KL/qzKgnAq1A== dependencies: + "@smithy/property-provider" "^2.0.10" + "@smithy/shared-ini-file-loader" "^2.0.11" + "@smithy/types" "^2.3.3" tslib "^2.5.0" "@smithy/node-config-provider@^2.0.3": @@ -3550,15 +3757,15 @@ "@smithy/types" "^1.2.0" tslib "^2.5.0" -"@smithy/node-http-handler@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-2.0.3.tgz#4878a427821759c93e63218e6f1aaea3bb82f523" - integrity sha512-wUO78aa0VVJVz54Lr1Nw6FYnkatbvh2saHgkT8fdtNWc7I/osaPMUJnRkBmTZZ5w+BIQ1rvr9dbGyYBTlRg2+Q== +"@smithy/node-http-handler@^2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-2.1.5.tgz#b1ad4c4b7cdbb5774aeeaaf0bd14b78c6c267460" + integrity sha512-52uF+BrZaFiBh+NT/bADiVDCQO91T+OwDRsuaAeWZC1mlCXFjAPPQdxeQohtuYOe9m7mPP/xIMNiqbe8jvndHA== dependencies: - "@smithy/abort-controller" "^2.0.3" - "@smithy/protocol-http" "^2.0.3" - "@smithy/querystring-builder" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/abort-controller" "^2.0.9" + "@smithy/protocol-http" "^3.0.5" + "@smithy/querystring-builder" "^2.0.9" + "@smithy/types" "^2.3.3" tslib "^2.5.0" "@smithy/property-provider@^2.0.0", "@smithy/property-provider@^2.0.3": @@ -3569,6 +3776,14 @@ "@smithy/types" "^2.2.0" tslib "^2.5.0" +"@smithy/property-provider@^2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-2.0.10.tgz#6ed80935deff770459717c402af26e925076f32b" + integrity sha512-YMBVfh0ZMmJtbsUn+WfSwR32iRljZPdRN0Tn2GAcdJ+ejX8WrBXD7Z0jIkQDrQZr8fEuuv5x8WxMIj+qVbsPQw== + dependencies: + "@smithy/types" "^2.3.3" + tslib "^2.5.0" + "@smithy/protocol-http@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-1.2.0.tgz#a554e4dabb14508f0bc2cdef9c3710e2b294be04" @@ -3577,12 +3792,12 @@ "@smithy/types" "^1.2.0" tslib "^2.5.0" -"@smithy/protocol-http@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-2.0.3.tgz#1f44f33e8ac89b6ec04db14faeb4835631014f8b" - integrity sha512-yzBYloviSLOwo2RT62vBRCPtk8mc/O2RMJfynEahbX8ZnduHpKaajvx3IuGubhamIbesi7M5HBVecDehBnlb9Q== +"@smithy/protocol-http@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-3.0.5.tgz#a143bf54382c6f7c8cdf2c67d3be101a9b7b486c" + integrity sha512-3t3fxj+ip4EPHRC2fQ0JimMxR/qCQ1LSQJjZZVZFgROnFLYWPDgUZqpoi7chr+EzatxJVXF/Rtoi5yLHOWCoZQ== dependencies: - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" tslib "^2.5.0" "@smithy/querystring-builder@^1.1.0": @@ -3594,12 +3809,12 @@ "@smithy/util-uri-escape" "^1.1.0" tslib "^2.5.0" -"@smithy/querystring-builder@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-2.0.3.tgz#0f6eb065ef577b64b2ac3dc286163b0a6d559753" - integrity sha512-HPSviVgGj9FT4jPdprkfSGF3nhFzpQMST1hOC1Oh6eaRB2KTQCsOZmS7U4IqGErVPafe6f/yRa1DV73B5gO50w== +"@smithy/querystring-builder@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-2.0.9.tgz#97e3731b6e6fef533ab0b063b0007f6a545c0291" + integrity sha512-Yt6CPF4j3j1cuwod/DRflbuXxBFjJm7gAjy6W1RE21Rz5/kfGFqiZBXWmmXwGtnnhiLThYwoHK4S6/TQtnx0Fg== dependencies: - "@smithy/types" "^2.2.0" + "@smithy/types" "^2.3.3" "@smithy/util-uri-escape" "^2.0.0" tslib "^2.5.0" @@ -3611,12 +3826,30 @@ "@smithy/types" "^2.2.0" tslib "^2.5.0" -"@smithy/service-error-classification@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-2.0.0.tgz#bbce07c9c529d9333d40db881fd4a1795dd84892" - integrity sha512-2z5Nafy1O0cTf69wKyNjGW/sNVMiqDnb4jgwfMG8ye8KnFJ5qmJpDccwIbJNhXIfbsxTg9SEec2oe1cexhMJvw== +"@smithy/querystring-parser@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-2.0.9.tgz#a372fcb652df0c8110aa3ffbf6bc6b512e11a78c" + integrity sha512-U6z4N743s4vrcxPW8p8+reLV0PjMCYEyb1/wtMVvv3VnbJ74gshdI8SR1sBnEh95cF8TxonmX5IxY25tS9qGfg== + dependencies: + "@smithy/types" "^2.3.3" + tslib "^2.5.0" + +"@smithy/service-error-classification@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-2.0.2.tgz#2fcc703ecb2c0f2880a53427a1ecd8530fcccc34" + integrity sha512-GTUd2j63gKy7A+ggvSdn2hc4sejG7LWfE+ZMF17vzWoNyqERWbRP7HTPS0d0Lwg1p6OQCAzvNigSrEIWVFt6iA== + dependencies: + "@smithy/types" "^2.3.3" + +"@smithy/shared-ini-file-loader@^2.0.11": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.11.tgz#33dcad2941884e0f9423b0cfc0f2d2bcc74425d3" + integrity sha512-Sf0u5C5px6eykXi6jImDTp+edvG3REtPjXnFWU/J+b7S2wkXwUqFXqBL5DdM4zC1F+M8u57ZT7NRqDwMOw7/Tw== + dependencies: + "@smithy/types" "^2.3.3" + tslib "^2.5.0" -"@smithy/shared-ini-file-loader@^2.0.0", "@smithy/shared-ini-file-loader@^2.0.3": +"@smithy/shared-ini-file-loader@^2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.3.tgz#e813a00801ea9287368577f908f64dc7a366606c" integrity sha512-1Vgco3K0rN5YG2OStoS2zUrBzdcFqgqp475rGdag206PCh7AHzmVSGXL6OpWPAqZl29WUqXfMP8tHOLG0H6vkA== @@ -3624,6 +3857,14 @@ "@smithy/types" "^2.2.0" tslib "^2.5.0" +"@smithy/shared-ini-file-loader@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.6.tgz#95dbc455e56a261ffe0b32bb3e640292b2f31798" + integrity sha512-NO6dHqho6APbVR0DxPtYoL4KXBqUeSM3Slsd103MOgL50YbzzsQmMLtDMZ87W8MlvvCN0tuiq+OrAO/rM7hTQg== + dependencies: + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + "@smithy/signature-v4@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-2.0.3.tgz#4260a2d8699b37cbafba471c50284b07c801b420" @@ -3638,14 +3879,14 @@ "@smithy/util-utf8" "^2.0.0" tslib "^2.5.0" -"@smithy/smithy-client@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-2.0.3.tgz#cc3a8ef84c904ba75aa702edcf79973aa0e23e09" - integrity sha512-YP0HakPOJgvX2wvPEAGH9GB3NfuQE8CmBhR13bWtqWuIErmJnInTiSQcLSc0QiXHclH/8Qlq+qjKCR7N/4wvtQ== +"@smithy/smithy-client@^2.1.6", "@smithy/smithy-client@^2.1.7": + version "2.1.7" + resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-2.1.7.tgz#76b1f3ad9d95bd32afea3113132549be66c5eb12" + integrity sha512-r6T/oiBQ8vCbGqObH4/h0YqD0jFB1hAS9KFRmuTfaNJueu/L2hjmjqFjv3PV5lkbNHTgUYraSv4cFQ1naxiELQ== dependencies: - "@smithy/middleware-stack" "^2.0.0" - "@smithy/types" "^2.2.0" - "@smithy/util-stream" "^2.0.3" + "@smithy/middleware-stack" "^2.0.3" + "@smithy/types" "^2.3.3" + "@smithy/util-stream" "^2.0.12" tslib "^2.5.0" "@smithy/types@^1.2.0": @@ -3662,15 +3903,38 @@ dependencies: tslib "^2.5.0" -"@smithy/url-parser@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-2.0.3.tgz#68015a83218b8efb92822273c5ee81c71240297d" - integrity sha512-O7NlbDL4kh+th6qwtL7wNRcPCuOXFRWJzWKywfB/Nv56N1F8KiK0KbPn1z7MU5du/0LgjAMvhkg0mVDyiMCnqw== +"@smithy/types@^2.2.2": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-2.2.2.tgz#bd8691eb92dd07ac33b83e0e1c45f283502b1bf7" + integrity sha512-4PS0y1VxDnELGHGgBWlDksB2LJK8TG8lcvlWxIsgR+8vROI7Ms8h1P4FQUx+ftAX2QZv5g1CJCdhdRmQKyonyw== + dependencies: + tslib "^2.5.0" + +"@smithy/types@^2.3.3": + version "2.3.3" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-2.3.3.tgz#8770dea9b0e36c404d99a867d50b2fa6454f28aa" + integrity sha512-zTdIPR9PvFVNRdIKMQu4M5oyTaycIbUqLheQqaOi9rTWPkgjGO2wDBxMA1rBHQB81aqAEv+DbSS4jfKyQMnXRA== + dependencies: + tslib "^2.5.0" + +"@smithy/url-parser@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-2.0.3.tgz#68015a83218b8efb92822273c5ee81c71240297d" + integrity sha512-O7NlbDL4kh+th6qwtL7wNRcPCuOXFRWJzWKywfB/Nv56N1F8KiK0KbPn1z7MU5du/0LgjAMvhkg0mVDyiMCnqw== dependencies: "@smithy/querystring-parser" "^2.0.3" "@smithy/types" "^2.2.0" tslib "^2.5.0" +"@smithy/url-parser@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-2.0.9.tgz#0ea656c5e9b167082861ff1ff82ebb7459b09ab3" + integrity sha512-NBnJ0NiY8z6E82Xd5VYUFQfKwK/wA/+QkKmpYUYP+cpH3aCzE6g2gvixd9vQKYjsIdRfNPCf+SFAozt8ljozOw== + dependencies: + "@smithy/querystring-parser" "^2.0.9" + "@smithy/types" "^2.3.3" + tslib "^2.5.0" + "@smithy/util-base64@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-2.0.0.tgz#1beeabfb155471d1d41c8d0603be1351f883c444" @@ -3686,10 +3950,10 @@ dependencies: tslib "^2.5.0" -"@smithy/util-body-length-node@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/util-body-length-node/-/util-body-length-node-2.0.0.tgz#4870b71cb9ded0123d984898ce952ce56896bc53" - integrity sha512-ZV7Z/WHTMxHJe/xL/56qZwSUcl63/5aaPAGjkfynJm4poILjdD4GmFI+V+YWabh2WJIjwTKZ5PNsuvPQKt93Mg== +"@smithy/util-body-length-node@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz#313a5f7c5017947baf5fa018bfc22628904bbcfa" + integrity sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw== dependencies: tslib "^2.5.0" @@ -3716,26 +3980,28 @@ dependencies: tslib "^2.5.0" -"@smithy/util-defaults-mode-browser@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.3.tgz#de860befc4571a7e0939b8668169890b43466de9" - integrity sha512-t9cirP55wYeSfDjjvPHSjNiuZj3wc9W3W3fjLXaVzuKKlKX98B9Vj7QM9WHJnFjJdsrYEwolLA8GVdqZeHOkHg== +"@smithy/util-defaults-mode-browser@^2.0.10": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.11.tgz#46807747f3ca21a13770fc49e4bfb2bbc61a59c8" + integrity sha512-0syV1Mz/mCQ7CG/MHKQfH+w86xq59jpD0EOXv5oe0WBXLmq2lWPpVHl2Y6+jQ+/9fYzyZ5NF+NC/WEIuiv690A== dependencies: - "@smithy/property-provider" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/property-provider" "^2.0.10" + "@smithy/smithy-client" "^2.1.7" + "@smithy/types" "^2.3.3" bowser "^2.11.0" tslib "^2.5.0" -"@smithy/util-defaults-mode-node@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.3.tgz#3c6955fe6a516f7ba7a3af5865d678a937a43751" - integrity sha512-Gca+fL0h+tl8cbvoLDMWCVzs1CL4jWLWvz/I6MCYZzaEAKkmd1qO4kPzBeGaI6hGA/IbrlWCFg7L+MTPzLwzfg== - dependencies: - "@smithy/config-resolver" "^2.0.3" - "@smithy/credential-provider-imds" "^2.0.3" - "@smithy/node-config-provider" "^2.0.3" - "@smithy/property-provider" "^2.0.3" - "@smithy/types" "^2.2.0" +"@smithy/util-defaults-mode-node@^2.0.12": + version "2.0.13" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.13.tgz#aebdc44696f9713d0e9e65ca140b45122710c1df" + integrity sha512-6BtCHYdw5Z8r6KpW8tRCc3yURgvcQwfIEeHhR70BeSOfx8T/TXPPjb8A+K45+KASspa3fzrsSxeIwB0sAeMoHA== + dependencies: + "@smithy/config-resolver" "^2.0.10" + "@smithy/credential-provider-imds" "^2.0.12" + "@smithy/node-config-provider" "^2.0.12" + "@smithy/property-provider" "^2.0.10" + "@smithy/smithy-client" "^2.1.7" + "@smithy/types" "^2.3.3" tslib "^2.5.0" "@smithy/util-hex-encoding@^2.0.0": @@ -3752,12 +4018,21 @@ dependencies: tslib "^2.5.0" -"@smithy/util-retry@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-2.0.0.tgz#7ac5d5f12383a9d9b2a43f9ff25f3866c8727c24" - integrity sha512-/dvJ8afrElasuiiIttRJeoS2sy8YXpksQwiM/TcepqdRVp7u4ejd9C4IQURHNjlfPUT7Y6lCDSa2zQJbdHhVTg== +"@smithy/util-middleware@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-2.0.2.tgz#9529ba2c57c26a57e4a59af88ac7c36c69cffb7d" + integrity sha512-UGPZM+Ja/vke5pc/S8G0LNiHpVirtjppsXO+GK9m9wbzRGzPJTfnZA/gERUUN/AfxEy/8SL7U1kd7u4t2X8K1w== + dependencies: + "@smithy/types" "^2.3.3" + tslib "^2.5.0" + +"@smithy/util-retry@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-2.0.2.tgz#a328ec9580a160faa2a25247543fa4bd036a7426" + integrity sha512-ovWiayUB38moZcLhSFFfUgB2IMb7R1JfojU20qSahjxAgfOZvDWme3eOYUMtAVnouZ9kYJiFgHLy27qRH4NeeA== dependencies: - "@smithy/service-error-classification" "^2.0.0" + "@smithy/service-error-classification" "^2.0.2" + "@smithy/types" "^2.3.3" tslib "^2.5.0" "@smithy/util-stream-node@^1.0.2": @@ -3770,14 +4045,14 @@ "@smithy/util-buffer-from" "^1.1.0" tslib "^2.5.0" -"@smithy/util-stream@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-2.0.3.tgz#39ce49f43e4622a6bf9b54226c284a4671138702" - integrity sha512-+8n2vIyp6o9KHGey0PoGatcDthwVb7C/EzWfqojXrHhZOXy6l+hnWlfoF8zVerKYH2CUtravdJKRTy7vdkOXfQ== +"@smithy/util-stream@^2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-2.0.12.tgz#12682792e368794c4b890a14db4ce85272e3259d" + integrity sha512-FOCpRLaj6gvSyUC5mJAACT+sPMPmp9sD1o+hVbUH/QxwZfulypA3ZIFdAg/59/IY0d/1Q4CTztsiHEB5LgjN4g== dependencies: - "@smithy/fetch-http-handler" "^2.0.3" - "@smithy/node-http-handler" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/fetch-http-handler" "^2.1.5" + "@smithy/node-http-handler" "^2.1.5" + "@smithy/types" "^2.3.3" "@smithy/util-base64" "^2.0.0" "@smithy/util-buffer-from" "^2.0.0" "@smithy/util-hex-encoding" "^2.0.0" @@ -3806,13 +4081,13 @@ "@smithy/util-buffer-from" "^2.0.0" tslib "^2.5.0" -"@smithy/util-waiter@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-2.0.3.tgz#e9001142bc3856aee19c26cab21b1857705c2335" - integrity sha512-3/Fzqoyecvh4cNvcHQDl1GznskXjGc9uZ8N6aoaPCKfsctgZad/J13xg8WC1UXc3PwKocHtuUvz0dRFDLaBppQ== +"@smithy/util-waiter@^2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-2.0.9.tgz#c9f1967f8313f194cb00a7d5c3f279643d4960d1" + integrity sha512-Hy9Cs0FtIacC1aVFk98bm/7CYqim9fnHAPRnV/SB2mj02ExYs/9Dn5SrNQmtTBTLCn65KqYnNVBNS8GuGpZOOw== dependencies: - "@smithy/abort-controller" "^2.0.3" - "@smithy/types" "^2.2.0" + "@smithy/abort-controller" "^2.0.9" + "@smithy/types" "^2.3.3" tslib "^2.5.0" "@solidity-parser/parser@^0.14.0": @@ -3894,10 +4169,10 @@ lodash "^4.17.15" ts-essentials "^7.0.1" -"@typechain/ethers-v5@^11.0.0": - version "11.1.1" - resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-11.1.1.tgz#23a358135a302140cf89a186592464dd6bbf1f98" - integrity sha512-D9WyUrCJ4Z5Gg8T00HWLpuqn1CqSDXlCiUOOpLaWoCbnZrE2jSIOUwR9blBZNo6LE5058e3niVu6xk205Et7tg== +"@typechain/ethers-v5@^11.1.2": + version "11.1.2" + resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-11.1.2.tgz#82510c1744f37a2f906b9e0532ac18c0b74ffe69" + integrity sha512-ID6pqWkao54EuUQa0P5RgjvfA3MYqxUQKpbGKERbsjBW5Ra7EIXvbMlPp2pcP5IAdUkyMCFYsP2SN5q7mPdLDQ== dependencies: lodash "^4.17.15" ts-essentials "^7.0.1" @@ -3907,17 +4182,17 @@ resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-7.2.1.tgz#bb16403c17754b0c4d5772d71d03b924a03d4c80" integrity sha512-YK8irIC+eMrrmtGx0H4ISn9GgzLd9dojZWJaMbjp1YHLl2VqqNFBNrL5Q3KjGf4VE3sf/4hmq6EhQZ7kZp1NoQ== -"@types/adm-zip@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@types/adm-zip/-/adm-zip-0.5.0.tgz#94c90a837ce02e256c7c665a6a1eb295906333c1" - integrity sha512-FCJBJq9ODsQZUNURo5ILAQueuA8WJhRvuihS3ke2iI25mJlfV2LK8jG2Qj2z2AWg8U0FtWWqBHVRetceLskSaw== +"@types/adm-zip@^0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@types/adm-zip/-/adm-zip-0.5.3.tgz#6f8a06ffad5fdafad0318fd0837fca763a04c682" + integrity sha512-LfeDIiFdvphelYY2aMWTyQBr5cTb1EL9Qcu19jFizdt2sL/jL+fy1fE8IgAKBFI5XfbGukaRDDM5PiJTrovAhA== dependencies: "@types/node" "*" -"@types/aws-lambda@^8.10.119": - version "8.10.119" - resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.119.tgz#aaf010a9c892b3e29a290e5c49bfe8bcec82c455" - integrity sha512-Vqm22aZrCvCd6I5g1SvpW151jfqwTzEZ7XJ3yZ6xaZG31nUEOEyzzVImjRcsN8Wi/QyPxId/x8GTtgIbsy8kEw== +"@types/aws-lambda@^8.10.125": + version "8.10.125" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.125.tgz#c2ba86f7d98fe1827a7b048e0d31a65a8b5aed8c" + integrity sha512-Vqw/WMlV4O1fJT6capim01v7VLDZkcX1n6Yhb52E7IfnMqYbNfwHfyDV8rRN42NLBtdDvfaqcCqs2K0fr5ljZw== "@types/babel__core@^7.1.14": version "7.20.1" @@ -3974,10 +4249,10 @@ "@types/connect" "*" "@types/node" "*" -"@types/chai@^4.3.5": - version "4.3.5" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.5.tgz#ae69bcbb1bebb68c4ac0b11e9d8ed04526b3562b" - integrity sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng== +"@types/chai@^4.3.9": + version "4.3.9" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.9.tgz#144d762491967db8c6dea38e03d2206c2623feec" + integrity sha512-69TtiDzu0bcmKQv3yg1Zx409/Kd7r0b5F1PfpYJfSHzLGtB53547V4u+9iqKYsTu/O2ai6KTb0TInNpvuQ3qmg== "@types/concat-stream@^1.6.0": version "1.6.1" @@ -4024,7 +4299,7 @@ "@types/range-parser" "*" "@types/send" "*" -"@types/express@4.17.17", "@types/express@^4.17.17": +"@types/express@4.17.17": version "4.17.17" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== @@ -4034,6 +4309,16 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/express@^4.17.20": + version "4.17.20" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.20.tgz#e7c9b40276d29e38a4e3564d7a3d65911e2aa433" + integrity sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/form-data@0.0.33": version "0.0.33" resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-0.0.33.tgz#c9ac85b2a5fd18435b8c85d9ecb50e6d6c893ff8" @@ -4095,10 +4380,10 @@ expect "^28.0.0" pretty-format "^28.0.0" -"@types/jest@^29.5.2": - version "29.5.3" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.3.tgz#7a35dc0044ffb8b56325c6802a4781a626b05777" - integrity sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA== +"@types/jest@^29.5.6": + version "29.5.7" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.7.tgz#2c0dafe2715dd958a455bc10e2ec3e1ec47b5036" + integrity sha512-HLyetab6KVPSiF+7pFcUyMeLsx25LDNDemw9mGsJBkai/oouwrjTycocSDYopMEwFhN2Y4s9oPyOCZNofgSt2g== dependencies: expect "^29.0.0" pretty-format "^29.0.0" @@ -4108,6 +4393,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== +"@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -4127,15 +4417,15 @@ "@types/level-errors" "*" "@types/node" "*" -"@types/libsodium-wrappers@^0.7.10": - version "0.7.10" - resolved "https://registry.yarnpkg.com/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz#a6ebde70d3b4af960fd802af8d0e3c7cfe281eb2" - integrity sha512-BqI9B92u+cM3ccp8mpHf+HzJ8fBlRwdmyd6+fz3p99m3V6ifT5O3zmOMi612PGkpeFeG/G6loxUnzlDNhfjPSA== +"@types/libsodium-wrappers@^0.7.12": + version "0.7.12" + resolved "https://registry.yarnpkg.com/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.12.tgz#0dfa2d66ab8bdc1312c0e2f4e7e1cd5633c6df57" + integrity sha512-NNUV6W5KFMYSazUh7bofvIqjHunu1ia24Q4gygXrhluXvvdPtkV6fXuciidYU7eBc9XTltAc6k727wYlrpo9Jg== -"@types/lodash@^4.14.195": - version "4.14.197" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.197.tgz#e95c5ddcc814ec3e84c891910a01e0c8a378c54b" - integrity sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g== +"@types/lodash@^4.14.200": + version "4.14.200" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.200.tgz#435b6035c7eba9cdf1e039af8212c9e9281e7149" + integrity sha512-YI/M/4HRImtNf3pJgbF+W6FrXovqj+T+/HpENLTooK9PnkacBsDpeP3IpHab40CClUfhNmdM2WTNP2sa2dni5Q== "@types/lru-cache@5.1.1", "@types/lru-cache@^5.1.0": version "5.1.1" @@ -4174,15 +4464,15 @@ dependencies: "@types/node" "*" -"@types/mocha@^10.0.1": - version "10.0.1" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b" - integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== +"@types/mocha@^10.0.3": + version "10.0.3" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.3.tgz#4804fe9cd39da26eb62fa65c15ea77615a187812" + integrity sha512-RsOPImTriV/OE4A9qKjMtk2MnXiuLLbcO3nCXK+kvq4nr0iMfFgpjaX3MPLb6f7+EL1FGSelYvuJMV6REH+ZPQ== -"@types/morgan@^1.9.4": - version "1.9.4" - resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.9.4.tgz#99965ad2bdc7c5cee28d8ce95cfa7300b19ea562" - integrity sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ== +"@types/morgan@^1.9.7": + version "1.9.7" + resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.9.7.tgz#ba1e980841be06cd164eedfba7e3e1e2f4d0c911" + integrity sha512-4sJFBUBrIZkP5EvMm1L6VCXp3SQe8dnXqlVpe1jsmTjS1JQVmSjnpMNs8DosQd6omBi/K7BSKJ6z/Mc3ki0K9g== dependencies: "@types/node" "*" @@ -4214,10 +4504,12 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== -"@types/node@^18.16.19": - version "18.17.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.17.5.tgz#c58b12bca8c2a437b38c15270615627e96dd0bc5" - integrity sha512-xNbS75FxH6P4UXTPUJp/zNPq6/xsfdJKussCWNOnz4aULWIRwMgP1LgaB5RiBnMX1DPCYenuqGZfnIAx5mbFLA== +"@types/node@^18.18.7": + version "18.18.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.8.tgz#2b285361f2357c8c8578ec86b5d097c7f464cfd6" + integrity sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ== + dependencies: + undici-types "~5.26.4" "@types/node@^8.0.0": version "8.10.66" @@ -4241,10 +4533,10 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== -"@types/prompts@^2.4.4": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-2.4.4.tgz#dd5a1d41cb1bcd0fc4464bf44a0c8354f36ea735" - integrity sha512-p5N9uoTH76lLvSAaYSZtBCdEXzpOOufsRjnhjVSrZGXikVGHX9+cc9ERtHRV4hvBKHyZb1bg4K+56Bd2TqUn4A== +"@types/prompts@^2.4.7": + version "2.4.7" + resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-2.4.7.tgz#d9f2e53b00639721eddc949289843cef4fb1679b" + integrity sha512-5zTamE+QQM4nR6Ab3yHK+ovWuhLJXaa2ZLt3mT1en8U3ubWtjVT1vXDaVFC2+cL89uVn7Y+gIq5B3IcVvBl5xQ== dependencies: "@types/node" "*" kleur "^3.0.3" @@ -4318,6 +4610,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + "@types/ws@*": version "8.5.5" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" @@ -4330,14 +4627,21 @@ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== -"@types/yargs@^17.0.24", "@types/yargs@^17.0.8": +"@types/yargs@^17.0.29": + version "17.0.29" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.29.tgz#06aabc72497b798c643c812a8b561537fea760cf" + integrity sha512-nacjqA3ee9zRF/++a3FUY1suHTFKZeHba2n8WeDw9cCVdmzmHpIxyzOJBcpHvvEmS8E9KqWlSnWHUkOrkhWcvA== + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^17.0.8": version "17.0.24" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.61.0": +"@typescript-eslint/eslint-plugin@^5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== @@ -4353,7 +4657,35 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.61.0": +"@typescript-eslint/eslint-plugin@^6.2.1": + version "6.12.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz#2a647d278bb48bf397fef07ba0507612ff9dd812" + integrity sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.12.0" + "@typescript-eslint/type-utils" "6.12.0" + "@typescript-eslint/utils" "6.12.0" + "@typescript-eslint/visitor-keys" "6.12.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@^5.4.2 || ^6.0.0", "@typescript-eslint/parser@^6.2.1": + version "6.12.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.12.0.tgz#9fb21ed7d88065a4a2ee21eb80b8578debb8217c" + integrity sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg== + dependencies: + "@typescript-eslint/scope-manager" "6.12.0" + "@typescript-eslint/types" "6.12.0" + "@typescript-eslint/typescript-estree" "6.12.0" + "@typescript-eslint/visitor-keys" "6.12.0" + debug "^4.3.4" + +"@typescript-eslint/parser@^5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== @@ -4371,6 +4703,14 @@ "@typescript-eslint/types" "5.62.0" "@typescript-eslint/visitor-keys" "5.62.0" +"@typescript-eslint/scope-manager@6.12.0": + version "6.12.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz#5833a16dbe19cfbad639d4d33bcca5e755c7044b" + integrity sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw== + dependencies: + "@typescript-eslint/types" "6.12.0" + "@typescript-eslint/visitor-keys" "6.12.0" + "@typescript-eslint/type-utils@5.62.0", "@typescript-eslint/type-utils@^5.50.0", "@typescript-eslint/type-utils@^5.55.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" @@ -4381,11 +4721,26 @@ debug "^4.3.4" tsutils "^3.21.0" +"@typescript-eslint/type-utils@6.12.0", "@typescript-eslint/type-utils@^6.0.0": + version "6.12.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz#968f7c95162808d69950ab5dff710ad730e58287" + integrity sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng== + dependencies: + "@typescript-eslint/typescript-estree" "6.12.0" + "@typescript-eslint/utils" "6.12.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/types@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== +"@typescript-eslint/types@6.12.0": + version "6.12.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.12.0.tgz#ffc5297bcfe77003c8b7b545b51c2505748314ac" + integrity sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q== + "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" @@ -4399,6 +4754,19 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@6.12.0": + version "6.12.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz#764ccc32598549e5b48ec99e3b85f89b1385310c" + integrity sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw== + dependencies: + "@typescript-eslint/types" "6.12.0" + "@typescript-eslint/visitor-keys" "6.12.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/utils@5.62.0", "@typescript-eslint/utils@^5.10.0", "@typescript-eslint/utils@^5.50.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" @@ -4413,6 +4781,19 @@ eslint-scope "^5.1.1" semver "^7.3.7" +"@typescript-eslint/utils@6.12.0", "@typescript-eslint/utils@^6.0.0", "@typescript-eslint/utils@^6.2.0": + version "6.12.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.12.0.tgz#c6ce8c06fe9b0212620e5674a2036f6f8f611754" + integrity sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.12.0" + "@typescript-eslint/types" "6.12.0" + "@typescript-eslint/typescript-estree" "6.12.0" + semver "^7.5.4" + "@typescript-eslint/visitor-keys@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" @@ -4421,10 +4802,23 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" -"@vercel/ncc@^0.36.1": - version "0.36.1" - resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.36.1.tgz#d4c01fdbbe909d128d1bf11c7f8b5431654c5b95" - integrity sha512-S4cL7Taa9yb5qbv+6wLgiKVZ03Qfkc4jGRuiUQMQ8HGBD5pcNRnHeYM33zBvJE4/zJGjJJ8GScB+WmTsn9mORw== +"@typescript-eslint/visitor-keys@6.12.0": + version "6.12.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz#5877950de42a0f3344261b7a1eee15417306d7e9" + integrity sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw== + dependencies: + "@typescript-eslint/types" "6.12.0" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@vercel/ncc@^0.38.1": + version "0.38.1" + resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.38.1.tgz#13f08738111e1d9e8a22fd6141f3590e54d9a60e" + integrity sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw== "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": version "1.11.6" @@ -4610,6 +5004,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== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -4909,6 +5308,13 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +aria-query@^5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" + integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== + dependencies: + dequal "^2.0.3" + array-back@^3.0.1, array-back@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" @@ -4942,15 +5348,15 @@ array-ify@^1.0.0: resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== -array-includes@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== +array-includes@^3.1.6, array-includes@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" + integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" is-string "^1.0.7" array-timsort@^1.0.3: @@ -4968,18 +5374,18 @@ array-uniq@1.0.3: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== -array.prototype.findlastindex@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz#bc229aef98f6bd0533a2bc61ff95209875526c9b" - integrity sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw== +array.prototype.findlastindex@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" + integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.1" -array.prototype.flat@^1.2.3, array.prototype.flat@^1.3.1: +array.prototype.flat@^1.2.3: version "1.3.1" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== @@ -4989,14 +5395,24 @@ array.prototype.flat@^1.2.3, array.prototype.flat@^1.3.1: es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" - integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" array.prototype.reduce@^1.0.5: @@ -5010,6 +5426,17 @@ array.prototype.reduce@^1.0.5: es-array-method-boxes-properly "^1.0.0" is-string "^1.0.7" +array.prototype.tosorted@^1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz#620eff7442503d66c799d95503f82b475745cefd" + integrity sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.2.1" + arraybuffer.prototype.slice@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz#9b5ea3868a6eebc30273da577eb888381c0044bb" @@ -5022,6 +5449,19 @@ arraybuffer.prototype.slice@^1.0.1: is-array-buffer "^3.0.2" is-shared-array-buffer "^1.0.2" +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -5059,6 +5499,11 @@ ast-parents@^0.0.1: resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" integrity sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA== +ast-types-flow@^0.0.8: + version "0.0.8" + resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" + integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== + ast-types@^0.13.4: version "0.13.4" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" @@ -5110,6 +5555,13 @@ async@^3.2.0, async@^3.2.3, async@~3.2.0: resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== +asynciterator.prototype@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" + integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg== + dependencies: + has-symbols "^1.0.3" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -5160,6 +5612,11 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== +axe-core@=4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" + integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== + axios@^0.21.0, axios@^0.21.1: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" @@ -5174,7 +5631,7 @@ axios@^0.24.0: dependencies: follow-redirects "^1.14.4" -axios@^1.0.0, axios@^1.4.0: +axios@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== @@ -5183,15 +5640,40 @@ axios@^1.0.0, axios@^1.4.0: form-data "^4.0.0" proxy-from-env "^1.1.0" -babel-jest@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.2.tgz#cada0a59e07f5acaeb11cbae7e3ba92aec9c1126" - integrity sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A== +axios@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" + integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +axios@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" + integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== dependencies: - "@jest/transform" "^29.6.2" + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +axobject-query@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" + integrity sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg== + dependencies: + dequal "^2.0.3" + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.5.0" + babel-preset-jest "^29.6.3" chalk "^4.0.0" graceful-fs "^4.2.9" slash "^3.0.0" @@ -5207,10 +5689,10 @@ babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" - integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" @@ -5235,12 +5717,12 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" - integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: - babel-plugin-jest-hoist "^29.5.0" + babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" balanced-match@^1.0.0: @@ -5306,11 +5788,16 @@ bigint-crypto-utils@^3.0.23: resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz#72ad00ae91062cf07f2b1def9594006c279c1d77" integrity sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg== -bignumber.js@^9.0.0, bignumber.js@^9.1.1: +bignumber.js@^9.0.0: version "9.1.1" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== +bignumber.js@^9.1.2: + version "9.1.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" + integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -5552,6 +6039,11 @@ bufferutil@4.0.5: dependencies: node-gyp-build "^4.3.0" +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" @@ -5607,6 +6099,15 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.4: + version "1.0.5" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -5658,18 +6159,18 @@ cbor@^8.1.0: dependencies: nofilter "^3.1.0" -chai@^4.3.7: - version "4.3.7" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51" - integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== +chai@^4.3.10: + version "4.3.10" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.10.tgz#d784cec635e3b7e2ffb66446a63b4e33bd390384" + integrity sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g== dependencies: assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^4.1.2" - get-func-name "^2.0.0" - loupe "^2.3.1" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" pathval "^1.1.1" - type-detect "^4.0.5" + type-detect "^4.0.8" chalk@3.0.0, chalk@~3.0.0: version "3.0.0" @@ -5724,10 +6225,12 @@ charm@~0.1.1: resolved "https://registry.yarnpkg.com/charm/-/charm-0.1.2.tgz#06c21eed1a1b06aeb67553cdc53e23274bac2296" integrity sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ== -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" chokidar@3.3.0: version "3.3.0" @@ -5779,6 +6282,11 @@ ci-info@^3.1.0, ci-info@^3.2.0, ci-info@^3.6.1: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== +ci-info@^3.8.0: + version "3.9.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -5803,6 +6311,13 @@ classic-level@^1.2.0: napi-macros "^2.2.2" node-gyp-build "^4.3.0" +clean-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz#8df7c7aae51fd36874e8f8d05b9180bc11a3fed7" + integrity sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw== + dependencies: + escape-string-regexp "^1.0.5" + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -5933,7 +6448,7 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -5952,26 +6467,50 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== +color@^3.1.3: + version "3.2.1" + resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + colorette@^2.0.14: version "2.0.20" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== -colors@1.4.0, colors@^1.1.2: +colors@1.4.0, colors@^1.1.2, colors@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + columnify@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" @@ -6064,7 +6603,7 @@ compare-func@^2.0.0: array-ify "^1.0.0" dot-prop "^5.1.0" -compare-versions@^6.0.0: +compare-versions@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" integrity sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg== @@ -6126,10 +6665,10 @@ continuation-local-storage@^3.2.1: async-listener "^0.6.0" emitter-listener "^1.1.1" -conventional-changelog-angular@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz#a9a9494c28b7165889144fd5b91573c4aa9ca541" - integrity sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg== +conventional-changelog-angular@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz#5eec8edbff15aa9b1680a8dcfbd53e2d7eb2ba7a" + integrity sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ== dependencies: compare-func "^2.0.0" @@ -6290,6 +6829,19 @@ create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -6358,6 +6910,11 @@ culvert@^0.1.2: resolved "https://registry.yarnpkg.com/culvert/-/culvert-0.1.2.tgz#9502f5f0154a2d5a22a023e79f71cc936fa6ef6f" integrity sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg== +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + dargs@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" @@ -6468,7 +7025,7 @@ dedent@^1.0.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== -deep-eql@^4.1.2: +deep-eql@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== @@ -6485,7 +7042,7 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -deepmerge-ts@^5.0.0: +deepmerge-ts@^5.0.0, deepmerge-ts@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/deepmerge-ts/-/deepmerge-ts-5.1.0.tgz#c55206cc4c7be2ded89b9c816cf3608884525d7a" integrity sha512-eS8dRJOckyo9maw9Tu5O5RUi/4inFLrnoLkBe3cPfDMx3WZioXtmOew4TXQaxq7Rhl4xjDtR7c6x8nNTxOvbFw== @@ -6510,6 +7067,15 @@ deferred-leveldown@~5.3.0: abstract-leveldown "~6.2.1" inherits "^2.0.3" +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + define-lazy-prop@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" @@ -6523,6 +7089,15 @@ define-properties@^1.1.2, define-properties@^1.1.3, define-properties@^1.1.4, de has-property-descriptors "^1.0.0" object-keys "^1.1.1" +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + degenerator@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-5.0.1.tgz#9403bf297c6dad9a1ece409b37db27954f91f2f5" @@ -6552,6 +7127,11 @@ deprecation@^2.0.0: resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== +dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -6590,6 +7170,11 @@ diff-sequences@^29.4.3: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + diff@3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -6772,6 +7357,11 @@ emojis-list@^3.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + encode-utf8@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" @@ -6806,7 +7396,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.15.0: +enhanced-resolve@^5.12.0, enhanced-resolve@^5.15.0: version "5.15.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== @@ -6913,11 +7503,76 @@ es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.2: unbox-primitive "^1.0.2" which-typed-array "^1.1.10" +es-abstract@^1.22.1: + version "1.22.2" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz#90f7282d91d0ad577f505e423e52d4c1d93c1b8a" + integrity sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA== + dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.1" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.12" + is-weakref "^1.0.2" + object-inspect "^1.12.3" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.11" + es-array-method-boxes-properly@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== +es-iterator-helpers@^1.0.12, es-iterator-helpers@^1.0.15: + version "1.0.15" + resolved "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" + integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== + dependencies: + asynciterator.prototype "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.1" + es-abstract "^1.22.1" + es-set-tostringtag "^2.0.1" + function-bind "^1.1.1" + get-intrinsic "^1.2.1" + globalthis "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + iterator.prototype "^1.1.2" + safe-array-concat "^1.0.1" + es-module-lexer@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.0.tgz#6be9c9e0b4543a60cd166ff6f8b4e9dae0b0c16f" @@ -6948,13 +7603,13 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -esbuild-loader@^3.0.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-3.2.0.tgz#78f11e1a2fd651758de490860acebda1c7e10131" - integrity sha512-lnIdRMQpk50alCa0QoW0ozc0D3rjJXl02mtMsk9INIcW25RPZhDja332bu85ixwVNbhQ7VfBRcQyZ/qza8mWiA== +esbuild-loader@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-4.0.2.tgz#5452fb40919d9a0959655522cd2732dc4c383e13" + integrity sha512-kj88m0yrtTEJDeUEF+3TZsq7t9VPzQQj7UmXAzUbIaipoYSrd0UxKAcg4l9CBgP8uVoploiw+nKr8DIv6Y9gXw== dependencies: esbuild "^0.19.0" - get-tsconfig "^4.6.2" + get-tsconfig "^4.7.0" loader-utils "^2.0.4" webpack-sources "^1.4.3" @@ -7034,7 +7689,22 @@ escodegen@^2.1.0: optionalDependencies: source-map "~0.6.1" -eslint-import-resolver-node@^0.3.7: +eslint-config-next@^13.1.6: + version "13.5.6" + resolved "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.5.6.tgz#3a5a6222d5cb32256760ad68ab8e976e866a08c8" + integrity sha512-o8pQsUHTo9aHqJ2YiZDym5gQAMRf7O2HndHo/JZeY7TDD+W4hk6Ma8Vw54RHiBeb7OWWO5dPirQB+Is/aVQ7Kg== + dependencies: + "@next/eslint-plugin-next" "13.5.6" + "@rushstack/eslint-patch" "^1.3.3" + "@typescript-eslint/parser" "^5.4.2 || ^6.0.0" + eslint-import-resolver-node "^0.3.6" + eslint-import-resolver-typescript "^3.5.2" + eslint-plugin-import "^2.28.1" + eslint-plugin-jsx-a11y "^6.7.1" + eslint-plugin-react "^7.33.2" + eslint-plugin-react-hooks "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + +eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: version "0.3.9" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== @@ -7043,13 +7713,50 @@ eslint-import-resolver-node@^0.3.7: is-core-module "^2.13.0" resolve "^1.22.4" -eslint-module-utils@^2.8.0: +eslint-import-resolver-typescript@^3.5.2: + version "3.6.1" + resolved "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa" + integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== + dependencies: + debug "^4.3.4" + enhanced-resolve "^5.12.0" + eslint-module-utils "^2.7.4" + fast-glob "^3.3.1" + get-tsconfig "^4.5.0" + is-core-module "^2.11.0" + is-glob "^4.0.3" + +eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== dependencies: debug "^3.2.7" +eslint-plugin-check-file@^2.6.2: + version "2.6.2" + resolved "https://registry.npmjs.org/eslint-plugin-check-file/-/eslint-plugin-check-file-2.6.2.tgz#2e60d567ce7d087727d19c7e7b5b9def1e5b693e" + integrity sha512-z3Rur4JjOdNH0fia1IH7JQseo9NLuFVtw9j8P6z2c5XmXWemH7/qGpmMB8XbOt9bJBNpmPlNAGJty9b3EervPw== + dependencies: + is-glob "^4.0.3" + micromatch "^4.0.5" + +eslint-plugin-cypress@^2.14.0: + version "2.15.1" + resolved "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.1.tgz#336afa7e8e27451afaf65aa359c9509e0a4f3a7b" + integrity sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w== + dependencies: + globals "^13.20.0" + +eslint-plugin-deprecation@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/eslint-plugin-deprecation/-/eslint-plugin-deprecation-2.0.0.tgz#9804707a4c19f3a53615c6babc0ced3d429d69cf" + integrity sha512-OAm9Ohzbj11/ZFyICyR5N6LbOIvQMp7ZU2zI7Ej0jIc8kiGUERXPNMfw2QqqHD1ZHtjMub3yPZILovYEYucgoQ== + dependencies: + "@typescript-eslint/utils" "^6.0.0" + tslib "^2.3.1" + tsutils "^3.21.0" + eslint-plugin-functional@^5.0.8: version "5.0.8" resolved "https://registry.yarnpkg.com/eslint-plugin-functional/-/eslint-plugin-functional-5.0.8.tgz#3b49718b2a717f196a3d077f970b6b698ccbe925" @@ -7062,37 +7769,140 @@ eslint-plugin-functional@^5.0.8: is-immutable-type "^1.2.5" semver "^7.3.8" -eslint-plugin-import@^2.27.5: - version "2.28.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz#8d66d6925117b06c4018d491ae84469eb3cb1005" - integrity sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q== +eslint-plugin-functional@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/eslint-plugin-functional/-/eslint-plugin-functional-6.0.0.tgz#37c32dd78443f156bb0b45febaa5d19f596cd7e7" + integrity sha512-jOUHUMA9cN2CIpgPj93fW1vTI3c95ZYUHMPJxEJL4KAtFkJDcT/9/YlfyrLOBxHkAcwBhJ29HSmeC/CUnN0k3g== dependencies: - array-includes "^3.1.6" - array.prototype.findlastindex "^1.2.2" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" + "@typescript-eslint/utils" "^6.2.0" + deepmerge-ts "^5.1.0" + escape-string-regexp "^4.0.0" + is-immutable-type "^2.0.1" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +eslint-plugin-import@^2.28.1, eslint-plugin-import@^2.29.0: + version "2.29.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155" + integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg== + dependencies: + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" + eslint-import-resolver-node "^0.3.9" eslint-module-utils "^2.8.0" - has "^1.0.3" - is-core-module "^2.12.1" + hasown "^2.0.0" + is-core-module "^2.13.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.fromentries "^2.0.6" - object.groupby "^1.0.0" - object.values "^1.1.6" - resolve "^1.22.3" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" semver "^6.3.1" tsconfig-paths "^3.14.2" -eslint-plugin-jest@^27.2.2: - version "27.2.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz#6f8a4bb2ca82c0c5d481d1b3be256ab001f5a3ec" - integrity sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ== +eslint-plugin-jest-formatting@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/eslint-plugin-jest-formatting/-/eslint-plugin-jest-formatting-3.1.0.tgz#b26dd5a40f432b642dcc880021a771bb1c93dcd2" + integrity sha512-XyysraZ1JSgGbLSDxjj5HzKKh0glgWf+7CkqxbTqb7zEhW7X2WHo5SBQ8cGhnszKN+2Lj3/oevBlHNbHezoc/A== + +eslint-plugin-jest@^27.4.2, eslint-plugin-jest@^27.6.0: + version "27.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.6.0.tgz#e5c0cf735b3c8cad0ef9db5b565b2fc99f5e55ed" + integrity sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng== dependencies: "@typescript-eslint/utils" "^5.10.0" +eslint-plugin-jsx-a11y@^6.7.1: + version "6.8.0" + resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz#2fa9c701d44fcd722b7c771ec322432857fcbad2" + integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA== + dependencies: + "@babel/runtime" "^7.23.2" + aria-query "^5.3.0" + array-includes "^3.1.7" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "=4.7.0" + axobject-query "^3.2.1" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" + es-iterator-helpers "^1.0.15" + hasown "^2.0.0" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" + minimatch "^3.1.2" + object.entries "^1.1.7" + object.fromentries "^2.0.7" + +eslint-plugin-lodash@^7.4.0: + version "7.4.0" + resolved "https://registry.npmjs.org/eslint-plugin-lodash/-/eslint-plugin-lodash-7.4.0.tgz#14a761547f126c92ff56789662a20a44f8bb6290" + integrity sha512-Tl83UwVXqe1OVeBRKUeWcfg6/pCW1GTRObbdnbEJgYwjxp5Q92MEWQaH9+dmzbRt6kvYU1Mp893E79nJiCSM8A== + dependencies: + lodash "^4.17.21" + +eslint-plugin-no-only-tests@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-3.1.0.tgz#f38e4935c6c6c4842bf158b64aaa20c366fe171b" + integrity sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw== + +eslint-plugin-promise@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816" + integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== + +"eslint-plugin-react-hooks@^4.5.0 || 5.0.0-canary-7118f5dd7-20230705", eslint-plugin-react-hooks@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== + +eslint-plugin-react@^7.32.1, eslint-plugin-react@^7.33.2: + version "7.33.2" + resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" + integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== + dependencies: + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" + array.prototype.tosorted "^1.1.1" + doctrine "^2.1.0" + es-iterator-helpers "^1.0.12" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.6" + object.fromentries "^2.0.6" + object.hasown "^1.1.2" + object.values "^1.1.6" + prop-types "^15.8.1" + resolve "^2.0.0-next.4" + semver "^6.3.1" + string.prototype.matchall "^4.0.8" + +eslint-plugin-unicorn@^48.0.1: + version "48.0.1" + resolved "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-48.0.1.tgz#a6573bc1687ae8db7121fdd8f92394b6549a6959" + integrity sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + "@eslint-community/eslint-utils" "^4.4.0" + ci-info "^3.8.0" + clean-regexp "^1.0.0" + esquery "^1.5.0" + indent-string "^4.0.0" + is-builtin-module "^3.2.1" + jsesc "^3.0.2" + lodash "^4.17.21" + pluralize "^8.0.0" + read-pkg-up "^7.0.1" + regexp-tree "^0.1.27" + regjsparser "^0.10.0" + semver "^7.5.4" + strip-indent "^3.0.0" + eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -7114,18 +7924,19 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.44.0: - version "8.47.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.47.0.tgz#c95f9b935463fb4fad7005e626c7621052e90806" - integrity sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q== +eslint@^8.52.0: + version "8.52.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc" + integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "^8.47.0" - "@humanwhocodes/config-array" "^0.11.10" + "@eslint/js" "8.52.0" + "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -7176,7 +7987,7 @@ esprima@^4.0.0, esprima@^4.0.1: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.2: +esquery@^1.4.2, esquery@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== @@ -7200,7 +8011,7 @@ estraverse@^4.1.1: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0, estraverse@^5.2.0: +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -7354,7 +8165,7 @@ ethers@^4.0.40: uuid "2.0.1" xmlhttprequest "1.8.0" -ethers@^5.5.3, ethers@^5.7.1, ethers@^5.7.2: +ethers@^5.7.0, ethers@^5.7.1, ethers@^5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -7490,7 +8301,7 @@ expect@^28.0.0: jest-message-util "^28.1.3" jest-util "^28.1.3" -expect@^29.0.0, expect@^29.6.2: +expect@^29.0.0: version "29.6.2" resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.2.tgz#7b08e83eba18ddc4a2cf62b5f2d1918f5cd84521" integrity sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA== @@ -7502,6 +8313,17 @@ expect@^29.0.0, expect@^29.6.2: jest-message-util "^29.6.2" jest-util "^29.6.2" +expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + exponential-backoff@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" @@ -7594,7 +8416,7 @@ fast-glob@3.2.7: merge2 "^1.3.0" micromatch "^4.0.4" -fast-glob@^3.0.3, fast-glob@^3.2.9, fast-glob@^3.3.0: +fast-glob@^3.0.3, fast-glob@^3.2.9, fast-glob@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== @@ -7658,6 +8480,11 @@ fclone@1.0.11, fclone@~1.0.11: resolved "https://registry.yarnpkg.com/fclone/-/fclone-1.0.11.tgz#10e85da38bfea7fc599341c296ee1d77266ee640" integrity sha512-GDqVQezKzRABdeqflsgMr7ktzgF9CyS+p2oe0jJqUY6izSSbhPIQJDpoU4PtGcD7VPM9xh/dVrTu6z1nwgmEGw== +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + figures@3.2.0, figures@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -7776,6 +8603,11 @@ fmix@^0.1.0: dependencies: imul "^1.0.0" +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.14.4, follow-redirects@^1.15.0: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" @@ -7948,6 +8780,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + function.prototype.name@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" @@ -7958,6 +8795,16 @@ function.prototype.name@^1.1.5: es-abstract "^1.19.0" functions-have-names "^1.2.2" +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + functional-red-black-tree@^1.0.1, functional-red-black-tree@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" @@ -8027,10 +8874,10 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: version "1.2.1" @@ -8085,7 +8932,14 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" -get-tsconfig@^4.6.2: +get-tsconfig@^4.5.0: + version "4.7.2" + resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" + integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== + dependencies: + resolve-pkg-maps "^1.0.0" + +get-tsconfig@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.0.tgz#06ce112a1463e93196aa90320c35df5039147e34" integrity sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw== @@ -8241,7 +9095,7 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^10.2.2, glob@^10.2.5: +glob@^10.2.2: version "10.3.3" resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.3.tgz#8360a4ffdd6ed90df84aa8d52f21f452e86a123b" integrity sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw== @@ -8252,6 +9106,17 @@ glob@^10.2.2, glob@^10.2.5: minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-scurry "^1.10.1" +glob@^10.3.7: + version "10.3.10" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.5" + minimatch "^9.0.1" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" + glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" @@ -8324,6 +9189,13 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" +globals@^13.20.0: + version "13.23.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" + integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== + dependencies: + type-fest "^0.20.2" + globalthis@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" @@ -8435,10 +9307,10 @@ hard-rejection@^2.1.0: resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== -hardhat-deploy@^0.11.34: - version "0.11.36" - resolved "https://registry.yarnpkg.com/hardhat-deploy/-/hardhat-deploy-0.11.36.tgz#a0514267edb0b1405139487d889d17e7a91a9dce" - integrity sha512-xsegyeI+zYo858rLB09tk/GqlJ4PV5Pr2zbncAhL60WntichKrtizxRchZUr/F7J6ljUYAzTDchNKb5wIYcQqg== +hardhat-deploy@^0.11.43: + version "0.11.43" + resolved "https://registry.yarnpkg.com/hardhat-deploy/-/hardhat-deploy-0.11.43.tgz#b22ff15b3ea201b72ba0f17f4b2e182cc950e73e" + integrity sha512-D760CjDtinwjOCpKOvdyRtIJYLQIYXmhfgkFe+AkxlYM9bPZ/T4tZ/xIB2tR89ZT+z0hF1YuZFBXIL3/G/9T5g== dependencies: "@ethersproject/abi" "^5.7.0" "@ethersproject/abstract-signer" "^5.7.0" @@ -8457,7 +9329,7 @@ hardhat-deploy@^0.11.34: chokidar "^3.5.2" debug "^4.3.2" enquirer "^2.3.6" - ethers "^5.5.3" + ethers "^5.7.0" form-data "^4.0.0" fs-extra "^10.0.0" match-all "^1.2.6" @@ -8614,6 +9486,13 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -8968,6 +9847,18 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -8995,6 +9886,13 @@ is-buffer@^2.0.5, is-buffer@~2.0.3: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" @@ -9007,14 +9905,21 @@ is-ci@3.0.1, is-ci@^3.0.1: dependencies: ci-info "^3.2.0" -is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.5.0, is-core-module@^2.8.1: +is-core-module@^2.11.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-core-module@^2.13.0, is-core-module@^2.5.0, is-core-module@^2.8.1: version "2.13.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== dependencies: has "^1.0.3" -is-date-object@^1.0.1: +is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== @@ -9031,6 +9936,13 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-finalizationregistry@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== + dependencies: + call-bind "^1.0.2" + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -9046,7 +9958,7 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-generator-function@^1.0.7: +is-generator-function@^1.0.10, is-generator-function@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== @@ -9072,6 +9984,14 @@ is-immutable-type@^1.2.5: dependencies: "@typescript-eslint/type-utils" "^5.55.0" +is-immutable-type@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/is-immutable-type/-/is-immutable-type-2.0.1.tgz#5a968a045689d5094d553802d2282a83cfa2ba13" + integrity sha512-SNO0yWLzSN+oYb8adM4AvsPYSCqElmjcXUNemryDLo0r5M54oMs/6R4cvKLc9QtIs/nRuc3ahlgJoMdGfcHLwQ== + dependencies: + "@typescript-eslint/type-utils" "^6.0.0" + ts-api-utils "^1.0.1" + is-interactive@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" @@ -9082,6 +10002,11 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== +is-map@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -9139,6 +10064,11 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-set@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -9191,7 +10121,7 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" -is-typed-array@^1.1.10, is-typed-array@^1.1.3, is-typed-array@^1.1.9: +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.3, is-typed-array@^1.1.9: version "1.1.12" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== @@ -9213,6 +10143,11 @@ is-url@^1.2.4: resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -9220,6 +10155,14 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + is-windows@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -9262,6 +10205,11 @@ isomorphic-ws@^4.0.1: resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== +isows@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.3.tgz#93c1cf0575daf56e7120bab5c8c448b0809d0d74" + integrity sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -9272,7 +10220,7 @@ istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: +istanbul-lib-instrument@^5.0.4: version "5.2.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== @@ -9283,6 +10231,17 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz#7a8af094cbfff1d5bb280f62ce043695ae8dd5b8" + integrity sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + istanbul-lib-report@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" @@ -9309,6 +10268,17 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +iterator.prototype@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" + integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== + dependencies: + define-properties "^1.2.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + reflect.getprototypeof "^1.0.4" + set-function-name "^2.0.1" + jackspeak@^2.0.3: version "2.2.3" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.2.3.tgz#ac63c57c18d254dc78a1f4ecd1cdeb4daeb6e616" @@ -9318,6 +10288,15 @@ jackspeak@^2.0.3: optionalDependencies: "@pkgjs/parseargs" "^0.11.0" +jackspeak@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jake@^10.8.5: version "10.8.7" resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.7.tgz#63a32821177940c33f356e0ba44ff9d34e1c7d8f" @@ -9328,83 +10307,83 @@ jake@^10.8.5: filelist "^1.0.4" minimatch "^3.1.2" -jest-changed-files@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" - integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: execa "^5.0.0" + jest-util "^29.7.0" p-limit "^3.1.0" -jest-circus@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.6.2.tgz#1e6ffca60151ac66cad63fce34f443f6b5bb4258" - integrity sha512-G9mN+KOYIUe2sB9kpJkO9Bk18J4dTDArNFPwoZ7WKHKel55eKIS/u2bLthxgojwlf9NLCVQfgzM/WsOVvoC6Fw== +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== dependencies: - "@jest/environment" "^29.6.2" - "@jest/expect" "^29.6.2" - "@jest/test-result" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" dedent "^1.0.0" is-generator-fn "^2.0.0" - jest-each "^29.6.2" - jest-matcher-utils "^29.6.2" - jest-message-util "^29.6.2" - jest-runtime "^29.6.2" - jest-snapshot "^29.6.2" - jest-util "^29.6.2" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" p-limit "^3.1.0" - pretty-format "^29.6.2" + pretty-format "^29.7.0" pure-rand "^6.0.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-cli@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.6.2.tgz#edb381763398d1a292cd1b636a98bfa5644b8fda" - integrity sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q== +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: - "@jest/core" "^29.6.2" - "@jest/test-result" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" chalk "^4.0.0" + create-jest "^29.7.0" exit "^0.1.2" - graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^29.6.2" - jest-util "^29.6.2" - jest-validate "^29.6.2" - prompts "^2.0.1" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" yargs "^17.3.1" -jest-config@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.6.2.tgz#c68723f06b31ca5e63030686e604727d406cd7c3" - integrity sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw== +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== dependencies: "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.6.2" - "@jest/types" "^29.6.1" - babel-jest "^29.6.2" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^29.6.2" - jest-environment-node "^29.6.2" - jest-get-type "^29.4.3" - jest-regex-util "^29.4.3" - jest-resolve "^29.6.2" - jest-runner "^29.6.2" - jest-util "^29.6.2" - jest-validate "^29.6.2" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^29.6.2" + pretty-format "^29.7.0" slash "^3.0.0" strip-json-comments "^3.1.1" @@ -9428,35 +10407,45 @@ jest-diff@^28.1.3: jest-get-type "^28.0.2" pretty-format "^28.1.3" -jest-docblock@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" - integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== dependencies: - detect-newline "^3.0.0" + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-each@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.6.2.tgz#c9e4b340bcbe838c73adf46b76817b15712d02ce" - integrity sha512-MsrsqA0Ia99cIpABBc3izS1ZYoYfhIy0NNWqPSE0YXbQjwchyt6B1HD2khzyPe1WiJA7hbxXy77ZoUQxn8UlSw== +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== dependencies: - "@jest/types" "^29.6.1" - chalk "^4.0.0" - jest-get-type "^29.4.3" - jest-util "^29.6.2" - pretty-format "^29.6.2" + detect-newline "^3.0.0" -jest-environment-node@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.6.2.tgz#a9ea2cabff39b08eca14ccb32c8ceb924c8bb1ad" - integrity sha512-YGdFeZ3T9a+/612c5mTQIllvWkddPbYcN2v95ZH24oWMbGA4GGS2XdIF92QMhUhvrjjuQWYgUGW2zawOyH63MQ== +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: - "@jest/environment" "^29.6.2" - "@jest/fake-timers" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.6.2" - jest-util "^29.6.2" + jest-mock "^29.7.0" + jest-util "^29.7.0" jest-get-type@^28.0.2: version "28.0.2" @@ -9468,32 +10457,37 @@ jest-get-type@^29.4.3: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== -jest-haste-map@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.2.tgz#298c25ea5255cfad8b723179d4295cf3a50a70d1" - integrity sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA== +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" - jest-regex-util "^29.4.3" - jest-util "^29.6.2" - jest-worker "^29.6.2" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" micromatch "^4.0.4" walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-leak-detector@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.6.2.tgz#e2b307fee78cab091c37858a98c7e1d73cdf5b38" - integrity sha512-aNqYhfp5uYEO3tdWMb2bfWv6f0b4I0LOxVRpnRLAeque2uqOVVMLh6khnTcE2qJ5wAKop0HcreM1btoysD6bPQ== +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: - jest-get-type "^29.4.3" - pretty-format "^29.6.2" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" jest-matcher-utils@^28.1.3: version "28.1.3" @@ -9515,6 +10509,16 @@ jest-matcher-utils@^29.6.2: jest-get-type "^29.4.3" pretty-format "^29.6.2" +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + jest-message-util@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d" @@ -9545,127 +10549,142 @@ jest-message-util@^29.6.2: slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.2.tgz#ef9c9b4d38c34a2ad61010a021866dad41ce5e00" - integrity sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg== +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== dependencies: - "@jest/types" "^29.6.1" + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" "@types/node" "*" - jest-util "^29.6.2" + jest-util "^29.7.0" jest-pnp-resolver@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" - integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== -jest-resolve-dependencies@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.2.tgz#36435269b6672c256bcc85fb384872c134cc4cf2" - integrity sha512-LGqjDWxg2fuQQm7ypDxduLu/m4+4Lb4gczc13v51VMZbVP5tSBILqVx8qfWcsdP8f0G7aIqByIALDB0R93yL+w== +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: - jest-regex-util "^29.4.3" - jest-snapshot "^29.6.2" + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" -jest-resolve@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.6.2.tgz#f18405fe4b50159b7b6d85e81f6a524d22afb838" - integrity sha512-G/iQUvZWI5e3SMFssc4ug4dH0aZiZpsDq9o1PtXTV1210Ztyb2+w+ZgQkB3iOiC5SmAEzJBOHWz6Hvrd+QnNPw== +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^29.6.2" + jest-haste-map "^29.7.0" jest-pnp-resolver "^1.2.2" - jest-util "^29.6.2" - jest-validate "^29.6.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" resolve "^1.20.0" resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.6.2.tgz#89e8e32a8fef24781a7c4c49cd1cb6358ac7fc01" - integrity sha512-wXOT/a0EspYgfMiYHxwGLPCZfC0c38MivAlb2lMEAlwHINKemrttu1uSbcGbfDV31sFaPWnWJPmb2qXM8pqZ4w== +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== dependencies: - "@jest/console" "^29.6.2" - "@jest/environment" "^29.6.2" - "@jest/test-result" "^29.6.2" - "@jest/transform" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" emittery "^0.13.1" graceful-fs "^4.2.9" - jest-docblock "^29.4.3" - jest-environment-node "^29.6.2" - jest-haste-map "^29.6.2" - jest-leak-detector "^29.6.2" - jest-message-util "^29.6.2" - jest-resolve "^29.6.2" - jest-runtime "^29.6.2" - jest-util "^29.6.2" - jest-watcher "^29.6.2" - jest-worker "^29.6.2" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" p-limit "^3.1.0" source-map-support "0.5.13" -jest-runtime@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.6.2.tgz#692f25e387f982e89ab83270e684a9786248e545" - integrity sha512-2X9dqK768KufGJyIeLmIzToDmsN0m7Iek8QNxRSI/2+iPFYHF0jTwlO3ftn7gdKd98G/VQw9XJCk77rbTGZnJg== - dependencies: - "@jest/environment" "^29.6.2" - "@jest/fake-timers" "^29.6.2" - "@jest/globals" "^29.6.2" - "@jest/source-map" "^29.6.0" - "@jest/test-result" "^29.6.2" - "@jest/transform" "^29.6.2" - "@jest/types" "^29.6.1" +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^29.6.2" - jest-message-util "^29.6.2" - jest-mock "^29.6.2" - jest-regex-util "^29.4.3" - jest-resolve "^29.6.2" - jest-snapshot "^29.6.2" - jest-util "^29.6.2" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" strip-bom "^4.0.0" -jest-snapshot@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.6.2.tgz#9b431b561a83f2bdfe041e1cab8a6becdb01af9c" - integrity sha512-1OdjqvqmRdGNvWXr/YZHuyhh5DeaLp1p/F8Tht/MrMw4Kr1Uu/j4lRG+iKl1DAqUJDWxtQBMk41Lnf/JETYBRA== +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" "@babel/plugin-syntax-jsx" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.6.2" - "@jest/transform" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^29.6.2" + expect "^29.7.0" graceful-fs "^4.2.9" - jest-diff "^29.6.2" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.6.2" - jest-message-util "^29.6.2" - jest-util "^29.6.2" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" natural-compare "^1.4.0" - pretty-format "^29.6.2" + pretty-format "^29.7.0" semver "^7.5.3" jest-util@^28.1.3: @@ -9692,30 +10711,42 @@ jest-util@^29.0.0, jest-util@^29.6.2: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.2.tgz#25d972af35b2415b83b1373baf1a47bb266c1082" - integrity sha512-vGz0yMN5fUFRRbpJDPwxMpgSXW1LDKROHfBopAvDcmD6s+B/s8WJrwi+4bfH4SdInBA5C3P3BI19dBtKzx1Arg== +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^29.4.3" + jest-get-type "^29.6.3" leven "^3.1.0" - pretty-format "^29.6.2" + pretty-format "^29.7.0" -jest-watcher@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.6.2.tgz#77c224674f0620d9f6643c4cfca186d8893ca088" - integrity sha512-GZitlqkMkhkefjfN/p3SJjrDaxPflqxEAv3/ik10OirZqJGYH5rPiIsgVcfof0Tdqg3shQGdEIxDBx+B4tuLzA== +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: - "@jest/test-result" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" emittery "^0.13.1" - jest-util "^29.6.2" + jest-util "^29.7.0" string-length "^4.0.1" jest-worker@^27.4.5: @@ -9727,25 +10758,25 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jest-worker@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.2.tgz#682fbc4b6856ad0aa122a5403c6d048b83f3fb44" - integrity sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ== +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: "@types/node" "*" - jest-util "^29.6.2" + jest-util "^29.7.0" merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^29.6.0: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.6.2.tgz#3bd55b9fd46a161b2edbdf5f1d1bd0d1eab76c42" - integrity sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg== +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: - "@jest/core" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" import-local "^3.0.2" - jest-cli "^29.6.2" + jest-cli "^29.7.0" js-git@^0.7.8: version "0.7.8" @@ -9777,7 +10808,7 @@ js-sha3@0.8.0, js-sha3@^0.8.0: resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== -js-tokens@^4.0.0: +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -9815,6 +10846,16 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + json-bigint@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" @@ -9922,6 +10963,16 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: + version "3.3.5" + resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" + integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + object.assign "^4.1.4" + object.values "^1.1.6" + just-extend@^4.0.2: version "4.2.1" resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" @@ -9992,18 +11043,35 @@ kleur@^4.1.5: resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +language-subtag-registry@^0.3.20: + version "0.3.22" + resolved "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" + integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== + +language-tags@^1.0.9: + version "1.0.9" + resolved "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" + integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== + dependencies: + language-subtag-registry "^0.3.20" + lazy@~1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" integrity sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA== -lerna@^7.1.1: - version "7.1.5" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-7.1.5.tgz#f65bde23d477382a221f9373f82d027825fa8622" - integrity sha512-5bvfmoIH4Czk5mdoLaRPYkM3M63Ei6+TOuXs3MgXmvqD8vs+vQpHuBVmiYFp5Mwsck3FkidJ+eTxfucltA2Lmw== +lerna@^7.4.1: + version "7.4.2" + resolved "https://registry.yarnpkg.com/lerna/-/lerna-7.4.2.tgz#03497125d7b7c8d463eebfe17a701b16bde2ad09" + integrity sha512-gxavfzHfJ4JL30OvMunmlm4Anw7d7Tq6tdVHzUukLdS9nWnxCN/QB21qR+VJYp5tcyXogHKbdUEGh6qmeyzxSA== dependencies: - "@lerna/child-process" "7.1.5" - "@lerna/create" "7.1.5" + "@lerna/child-process" "7.4.2" + "@lerna/create" "7.4.2" "@npmcli/run-script" "6.0.2" "@nx/devkit" ">=16.5.1 < 17" "@octokit/plugin-enterprise-rest" "6.0.1" @@ -10013,7 +11081,7 @@ lerna@^7.1.1: clone-deep "4.0.1" cmd-shim "6.0.1" columnify "1.6.0" - conventional-changelog-angular "6.0.0" + conventional-changelog-angular "7.0.0" conventional-changelog-core "5.0.1" conventional-recommended-bump "7.0.1" cosmiconfig "^8.2.0" @@ -10040,7 +11108,7 @@ lerna@^7.1.1: libnpmpublish "7.3.0" load-json-file "6.2.0" lodash "^4.17.21" - make-dir "3.1.0" + make-dir "4.0.0" minimatch "3.0.5" multimatch "5.0.0" node-fetch "2.6.7" @@ -10239,17 +11307,17 @@ libnpmpublish@7.3.0: sigstore "^1.4.0" ssri "^10.0.1" -libsodium-wrappers@^0.7.11: - version "0.7.11" - resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.11.tgz#53bd20606dffcc54ea2122133c7da38218f575f7" - integrity sha512-SrcLtXj7BM19vUKtQuyQKiQCRJPgbpauzl3s0rSwD+60wtHqSUuqcoawlMDheCJga85nKOQwxNYQxf/CKAvs6Q== +libsodium-wrappers@^0.7.13: + version "0.7.13" + resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz#83299e06ee1466057ba0e64e532777d2929b90d3" + integrity sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw== dependencies: - libsodium "^0.7.11" + libsodium "^0.7.13" -libsodium@^0.7.11: - version "0.7.11" - resolved "https://registry.yarnpkg.com/libsodium/-/libsodium-0.7.11.tgz#cd10aae7bcc34a300cc6ad0ac88fcca674cfbc2e" - integrity sha512-WPfJ7sS53I2s4iM58QxY3Inb83/6mjlYgcmZs7DJsvDlnmVUwNinBCi5vBT43P6bHRy01O4zsMU2CoVR6xJ40A== +libsodium@^0.7.13: + version "0.7.13" + resolved "https://registry.yarnpkg.com/libsodium/-/libsodium-0.7.13.tgz#230712ec0b7447c57b39489c48a4af01985fb393" + integrity sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw== lines-and-columns@^1.1.6: version "1.2.4" @@ -10395,12 +11463,31 @@ log-symbols@4.1.0, log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -loupe@^2.3.1: - version "2.3.6" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" - integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== +logform@^2.2.0, logform@^2.3.2, logform@^2.4.0: + version "2.6.0" + resolved "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz#8c82a983f05d6eaeb2d75e3decae7a768b2bf9b5" + integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== dependencies: - get-func-name "^2.0.0" + get-func-name "^2.0.1" lru-cache@^4.0.1: version "4.1.5" @@ -10444,12 +11531,12 @@ ltgt@~2.2.0: resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== -make-dir@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== +make-dir@4.0.0, make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== dependencies: - semver "^6.0.0" + semver "^7.5.3" make-dir@^2.1.0: version "2.1.0" @@ -10459,13 +11546,6 @@ make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" - integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== - dependencies: - semver "^7.5.3" - make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -10635,7 +11715,7 @@ micro-ftch@^0.3.1: resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== -micromatch@^4.0.2, micromatch@^4.0.4: +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -10864,37 +11944,7 @@ mnemonist@^0.38.0: dependencies: obliterator "^2.0.0" -mocha@7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.1.2.tgz#8e40d198acf91a52ace122cd7599c9ab857b29e6" - integrity sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA== - dependencies: - ansi-colors "3.2.3" - browser-stdout "1.3.1" - chokidar "3.3.0" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" - growl "1.10.5" - he "1.2.0" - js-yaml "3.13.1" - log-symbols "3.0.0" - minimatch "3.0.4" - mkdirp "0.5.5" - ms "2.1.1" - node-environment-flags "1.0.6" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" - wide-align "1.1.3" - yargs "13.3.2" - yargs-parser "13.1.2" - yargs-unparser "1.6.0" - -mocha@^10.0.0: +mocha@10.2.0, mocha@^10.0.0: version "10.2.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== @@ -11455,7 +12505,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.1.0: +object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -11490,14 +12540,23 @@ object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -object.fromentries@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" - integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== +object.entries@^1.1.6, object.entries@^1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" + integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.fromentries@^2.0.6, object.fromentries@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" + integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" object.getownpropertydescriptors@^2.0.3: version "2.1.6" @@ -11510,24 +12569,32 @@ object.getownpropertydescriptors@^2.0.3: es-abstract "^1.21.2" safe-array-concat "^1.0.0" -object.groupby@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.0.tgz#cb29259cf90f37e7bac6437686c1ea8c916d12a9" - integrity sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw== +object.groupby@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" + integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== dependencies: call-bind "^1.0.2" define-properties "^1.2.0" - es-abstract "^1.21.2" + es-abstract "^1.22.1" get-intrinsic "^1.2.1" -object.values@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" - integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== +object.hasown@^1.1.2: + version "1.1.3" + resolved "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz#6a5f2897bb4d3668b8e79364f98ccf971bda55ae" + integrity sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA== + dependencies: + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.values@^1.1.6, object.values@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" + integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" obliterator@^2.0.0: version "2.0.4" @@ -11560,6 +12627,13 @@ once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" @@ -12099,11 +13173,16 @@ prettier-plugin-solidity@^1.1.3: semver "^7.3.8" solidity-comments-extractor "^0.0.7" -prettier@^2.3.1, prettier@^2.7.1, prettier@^2.8.3, prettier@^2.8.8: +prettier@^2.3.1, prettier@^2.7.1, prettier@^2.8.3: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +prettier@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" + integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== + pretty-format@^28.0.0, pretty-format@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5" @@ -12123,6 +13202,15 @@ pretty-format@^29.0.0, pretty-format@^29.6.2: ansi-styles "^5.0.0" react-is "^18.0.0" +pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + proc-log@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" @@ -12180,6 +13268,15 @@ promzard@^1.0.0: dependencies: read "^2.0.0" +prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + protocols@^2.0.0, protocols@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" @@ -12311,6 +13408,11 @@ raw-body@2.5.2, raw-body@^2.4.1: iconv-lite "0.4.24" unpipe "1.0.0" +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-is@^18.0.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" @@ -12479,11 +13581,28 @@ reduce-flatten@^2.0.0: resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== +reflect.getprototypeof@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3" + integrity sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + globalthis "^1.0.3" + which-builtin-type "^1.1.3" + regenerator-runtime@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== +regexp-tree@^0.1.27: + version "0.1.27" + resolved "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" + integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== + regexp.prototype.flags@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" @@ -12493,6 +13612,22 @@ regexp.prototype.flags@^1.5.0: define-properties "^1.2.0" functions-have-names "^1.2.3" +regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" + +regjsparser@^0.10.0: + version "0.10.0" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz#b1ed26051736b436f22fdec1c8f72635f9f44892" + integrity sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA== + dependencies: + jsesc "~0.5.0" + reinterval@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/reinterval/-/reinterval-1.1.0.tgz#3361ecfa3ca6c18283380dd0bb9546f390f5ece7" @@ -12627,7 +13762,7 @@ resolve@1.17.0: dependencies: path-parse "^1.0.6" -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.3, resolve@^1.22.4: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.4: version "1.22.4" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== @@ -12636,6 +13771,15 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^2.0.0-next.4: + version "2.0.0-next.5" + resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -12693,12 +13837,12 @@ rimraf@^4.4.1: dependencies: glob "^9.2.0" -rimraf@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.1.tgz#0881323ab94ad45fec7c0221f27ea1a142f3f0d0" - integrity sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg== +rimraf@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.5.tgz#9be65d2d6e683447d2e9013da2bf451139a61ccf" + integrity sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A== dependencies: - glob "^10.2.5" + glob "^10.3.7" ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" @@ -12768,6 +13912,16 @@ safe-array-concat@^1.0.0: has-symbols "^1.0.3" isarray "^2.0.5" +safe-array-concat@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" + integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + isarray "^2.0.5" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -12787,6 +13941,11 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" +safe-stable-stringify@^2.3.1: + version "2.4.3" + resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== + "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -12872,12 +14031,12 @@ semver@7.5.3: dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: +semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.1.1, semver@^7.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@~7.5.0: +semver@^7.0.0, semver@^7.1.1, semver@^7.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@~7.5.0: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -12932,6 +14091,25 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +set-function-name@^2.0.0, set-function-name@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + setimmediate@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" @@ -13038,6 +14216,13 @@ sigstore@^1.3.0, sigstore@^1.4.0: "@sigstore/tuf" "^1.0.3" make-fetch-happen "^11.0.1" +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + sinon@^14.0.2: version "14.0.2" resolved "https://registry.yarnpkg.com/sinon/-/sinon-14.0.2.tgz#585a81a3c7b22cf950762ac4e7c28eb8b151c46f" @@ -13140,10 +14325,10 @@ solc@0.8.15: semver "^5.5.0" tmp "0.0.33" -solhint@^3.4.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.6.1.tgz#005b44ad31016e1821e99d2e99b8176c59fa3ebd" - integrity sha512-pS7Pl11Ujiew9XWaLDH0U+AFc6iK1RtLV0YETSpjHZXjUaNYi32mY+pi8Ap9vqmNfWodWKtG0bVQpatq84mL4g== +solhint@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.6.2.tgz#2b2acbec8fdc37b2c68206a71ba89c7f519943fe" + integrity sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ== dependencies: "@solidity-parser/parser" "^0.16.0" ajv "^6.12.6" @@ -13170,10 +14355,10 @@ solidity-comments-extractor@^0.0.7: resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== -solidity-coverage@^0.8.4: - version "0.8.4" - resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.4.tgz#c57a21979f5e86859c5198de9fbae2d3bc6324a5" - integrity sha512-xeHOfBOjdMF6hWTbt42iH4x+7j1Atmrf5OldDPMxI+i/COdExUxszOswD9qqvcBTaLGiOrrpnh9UZjSpt4rBsg== +solidity-coverage@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.5.tgz#64071c3a0c06a0cecf9a7776c35f49edc961e875" + integrity sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ== dependencies: "@ethersproject/abi" "^5.0.9" "@solidity-parser/parser" "^0.16.0" @@ -13187,7 +14372,7 @@ solidity-coverage@^0.8.4: globby "^10.0.1" jsonschema "^1.2.4" lodash "^4.17.15" - mocha "7.1.2" + mocha "10.2.0" node-emoji "^1.10.0" pify "^4.0.1" recursive-readdir "^2.2.2" @@ -13323,6 +14508,11 @@ ssri@^9.0.1: dependencies: minipass "^3.1.1" +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -13419,6 +14609,21 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" +string.prototype.matchall@^4.0.8: + version "4.0.10" + resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz#a1553eb532221d4180c51581d6072cd65d1ee100" + integrity sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + regexp.prototype.flags "^1.5.0" + set-function-name "^2.0.0" + side-channel "^1.0.4" + string.prototype.trim@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" @@ -13428,6 +14633,15 @@ string.prototype.trim@^1.2.7: define-properties "^1.1.4" es-abstract "^1.20.4" +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string.prototype.trimend@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" @@ -13437,6 +14651,15 @@ string.prototype.trimend@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string.prototype.trimstart@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" @@ -13446,6 +14669,15 @@ string.prototype.trimstart@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -13729,6 +14961,11 @@ text-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -13818,6 +15055,16 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + +ts-api-utils@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" + integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== + ts-command-line-args@^2.2.0: version "2.5.1" resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz#e64456b580d1d4f6d948824c274cf6fa5f45f7f0" @@ -13982,7 +15229,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5, type-detect@^4.0.8: +type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== @@ -14035,7 +15282,7 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typechain@^8.0.0, typechain@^8.2.0: +typechain@^8.0.0: version "8.3.1" resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.3.1.tgz#dccbc839b94877997536c356380eff7325395cfb" integrity sha512-fA7clol2IP/56yq6vkMTR+4URF1nGjV82Wx6Rf09EsqD4tkzMAvEaqYxVFCavJm/1xaRga/oD55K+4FtuXwQOQ== @@ -14051,6 +15298,22 @@ typechain@^8.0.0, typechain@^8.2.0: ts-command-line-args "^2.2.0" ts-essentials "^7.0.1" +typechain@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.3.2.tgz#1090dd8d9c57b6ef2aed3640a516bdbf01b00d73" + integrity sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q== + dependencies: + "@types/prettier" "^2.1.1" + debug "^4.3.1" + fs-extra "^7.0.0" + glob "7.1.7" + js-sha3 "^0.8.0" + lodash "^4.17.15" + mkdirp "^1.0.4" + prettier "^2.3.1" + ts-command-line-args "^2.2.0" + ts-essentials "^7.0.1" + typed-array-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" @@ -14095,11 +15358,16 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -"typescript@>=3 < 6", typescript@^5.1.6: +"typescript@>=3 < 6": version "5.1.6" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== +typescript@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== + typical@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" @@ -14125,6 +15393,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + undici@^5.14.0: version "5.23.0" resolved "https://registry.yarnpkg.com/undici/-/undici-5.23.0.tgz#e7bdb0ed42cebe7b7aca87ced53e6eaafb8f8ca0" @@ -14307,6 +15580,20 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.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" @@ -14403,10 +15690,10 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.88.1: - version "5.88.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" - integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== +webpack@^5.89.0: + version "5.89.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.89.0.tgz#56b8bf9a34356e93a6625770006490bf3a7f32dc" + integrity sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.0" @@ -14452,6 +15739,34 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" +which-builtin-type@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" + integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== + dependencies: + function.prototype.name "^1.1.5" + has-tostringtag "^1.0.0" + is-async-function "^2.0.0" + is-date-object "^1.0.5" + is-finalizationregistry "^1.0.2" + is-generator-function "^1.0.10" + is-regex "^1.1.4" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + which-module@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" @@ -14476,6 +15791,17 @@ which-typed-array@^1.1.10, which-typed-array@^1.1.11, which-typed-array@^1.1.2: gopd "^1.0.1" has-tostringtag "^1.0.0" +which-typed-array@^1.1.9: + version "1.1.13" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + which@1.3.1, which@^1.1.1, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -14516,6 +15842,41 @@ wildcard@^2.0.0: resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== +winston-console-format@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/winston-console-format/-/winston-console-format-1.0.8.tgz#591adc8e9567c3397a3fa2e29e596d56e48db840" + integrity sha512-dq7t/E0D0QRi4XIOwu6HM1+5e//WPqylH88GVjKEhQVrzGFg34MCz+G7pMJcXFBen9C0kBsu5GYgbYsE2LDwKw== + dependencies: + colors "^1.4.0" + logform "^2.2.0" + triple-beam "^1.3.0" + +winston-transport@^4.5.0: + version "4.6.0" + resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz#f1c1a665ad1b366df72199e27892721832a19e1b" + integrity sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg== + dependencies: + logform "^2.3.2" + readable-stream "^3.6.0" + triple-beam "^1.3.0" + +winston@^3.10.0: + version "3.11.0" + resolved "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz#2d50b0a695a2758bb1c95279f0a88e858163ed91" + integrity sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.4.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.5.0" + word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" @@ -14626,7 +15987,7 @@ write-pkg@4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@*: +ws@*, ws@8.13.0: version "8.13.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== @@ -14808,7 +16169,7 @@ zksync-web3@^0.14.3: resolved "https://registry.yarnpkg.com/zksync-web3/-/zksync-web3-0.14.3.tgz#64ac2a16d597464c3fc4ae07447a8007631c57c9" integrity sha512-hT72th4AnqyLW1d5Jlv8N2B/qhEnl2NePK2A3org7tAa24niem/UAaHMkEvmWI3SF9waYUPtqAtjpf+yvQ9zvQ== -zod@^3.21.4: - version "3.22.0" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.0.tgz#2478211a9bf477eb2d7d2ce031b5f8ff0d596407" - integrity sha512-y5KZY/ssf5n7hCGDGGtcJO/EBJEm5Pa+QQvFBeyMOtnFYOSflalxIFFvdaYevPhePcmcKC4aTbFkCcXN7D0O8Q== +zod@^3.22.4: + version "3.22.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" + integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==